home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Examples / Calc / UCalc.inc1.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  135.5 KB  |  5,255 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UCalc.inc1.p}
  4. { Copyright © 1985 - 1990 by Apple Computer, Inc. All rights reserved. }
  5.  
  6. CONST
  7.     kTextScrapType        = 'TEXT';
  8.     kCalcScrapType        = 'CALC';
  9.  
  10.     kCellWidth            = 80;                            { default width of each cell }
  11.     kCellHeight         = 17;                            { default height of each cell }
  12.     kCellHBorder        = 2;                            { pixels separating cell contents from
  13.                                                          left/right edge }
  14.  
  15.     kCellFont            = applFont;
  16.     kCellFontSize        = 10;
  17.     kRowTitleWidth        = 32;                            { width of row titles }
  18.     kColumnTitleHeight    = 20;                            { height of column titles }
  19.     kTitlesFont         = applFont;                     { font for column/row titles }
  20.     kTitlesFontSize     = 10;                            { font size for column/row titles }
  21.  
  22.     kEntryFont            = applFont;                     { default font of cell contents }
  23.     kEntryFontSize        = 10;                            { default font size of cell contents }
  24.     kEntryHeight        = 20;                            { height of the cell entry view }
  25.  
  26.     kCalcMode            = Automatic;                    { default calculation mode }
  27.     kForceAutomatic     = TRUE;                         { force automatic calculation }
  28.     kSetDependents        = TRUE;                         { set cell's dependents }
  29.  
  30.     kDefaultJustification = TEJustCenter;                { default cell justification }
  31.     kNoJustification    = 2;                            { constant representing no justification }
  32.  
  33.     kValuePrecision     = 18;                            { digits of precision in our values }
  34.     kTELength            = (80 * 5);                     { number of characters in the text edit
  35.                                                          field }
  36.  
  37.     { Command Constants }
  38.  
  39.     cPrintSelection     = 180;
  40.     cRecalculate        = 401;
  41.     cAutoCalc            = 403;
  42.     cManualCalc         = 404;
  43.     cGeneral            = 501;
  44.     cNoDecimal            = 503;
  45.     cDecimal            = 504;
  46.     cScientific         = 505;
  47.     cSystemJustify        = 506;
  48.     cForceLeftJustify    = 507;
  49.     cRightJustify        = 508;
  50.     cCenter             = 509;
  51.     cSelection            = 1000;
  52.     cSizeColumn         = 1001;
  53.     cCutText            = 1103;
  54.     cCopyText            = 1104;
  55.     cClearText            = 1106;
  56.     cCutCells            = 1203;
  57.     cCopyCells            = 1204;
  58.     cClearCells         = 1206;
  59.     cStandardCut        = 1303;
  60.     cStandardCopy        = 1304;
  61.     cStandardClear        = 1306;
  62.  
  63.     { Cursor Resource ID's }
  64.  
  65.     kColumnSizingCursor = 256;                            { cursor for resizing a column }
  66.     kRowSizingCursor    = 257;                            { cursor for resizing a row--UNUSED }
  67.  
  68. TYPE
  69.     TypeOfLine            = (NoLine,                        { for DrawLine routine}
  70.                            SolidLine, BoldLine, VDottedLine, HDottedLine, RowSeparator,
  71.                            ColumnSeparator);
  72.  
  73. VAR
  74.     gGeneralFormat:     ValueFormat;                    { SANE conversion formats }
  75.     gDecimalFormat:     ValueFormat;
  76.     gNoDecimalFormat:    ValueFormat;
  77.     gScientificFormat:    ValueFormat;
  78.     gNoFormat:            ValueFormat;
  79.     gDefaultFormat:     FormatRecord;                    { default cell format }
  80.  
  81.     gColumnSeparatorPattern: Pattern;                    { patterns for separator lines }
  82.     gRowSeparatorPattern: Pattern;
  83.  
  84. {--------------------------------------------------------------------------------------------------}
  85.     {$S AFields}
  86.  
  87. PROCEDURE FormatFields(aTitle: Str255;
  88.                        VAR aFormat: FormatRecord;
  89.                        PROCEDURE DoToField(fieldName: Str255;
  90.                                            fieldAddr: Ptr;
  91.                                            fieldType: INTEGER));
  92.  
  93.     VAR
  94.         aString:            Str255;
  95.         anInteger:            INTEGER;
  96.         aStyle:             Style;
  97.  
  98.     BEGIN
  99.     { Because our brain-damaged compiler won't allow you to pass the address of byte-aligned
  100.       fields in packed records, we have to move the fields of a FormatRecord into a temporary
  101.       variable, then pass the address of the temporary. }
  102.  
  103.     DoToField(aTitle, NIL, bTitle);
  104.     WITH aFormat DO
  105.         BEGIN
  106.         CASE aFormat.fStyle OF
  107.             NoStyle:
  108.                 aString := 'NoStyle';
  109.             General:
  110.                 aString := 'General';
  111.             DecimalStyle:
  112.                 aString := 'DecimalStyle';
  113.             NoDecimal:
  114.                 aString := 'NoDecimal';
  115.             Scientific:
  116.                 aString := 'Scientific';
  117.             OTHERWISE
  118.                 aString := 'UnknownStyle';
  119.         END;
  120.         DoToField('  fStyle', @aString, bString);
  121.  
  122.         anInteger := fDigits;
  123.         DoToField('  fDigits', @anInteger, bInteger);
  124.  
  125.         CASE fJustification OF
  126.             teJustSystem:
  127.                 aString := 'System';
  128.             teForceLeft:
  129.                 aString := 'Forced Left';
  130.             TEJustCenter:
  131.                 aString := 'Center';
  132.             TEJustRight:
  133.                 aString := 'Right';
  134.             kNoJustification:
  135.                 aString := 'None';
  136.             OTHERWISE
  137.                 aString := 'Unknown';
  138.         END;
  139.         DoToField('  fJustification', @aString, bString);
  140.  
  141.         anInteger := fFontNumber;
  142.         DoToField('  fFontNumber', @anInteger, bFontName);
  143.         anInteger := fFontSize;
  144.         DoToField('  fFontSize', @anInteger, bInteger);
  145.         aStyle := fFontStyle;
  146.         DoToField('  fFontStyle', @aStyle, bStyle);
  147.         END;
  148.     END;
  149.  
  150. {--------------------------------------------------------------------------------------------------}
  151. {$S AReadFile}
  152.  
  153. PROCEDURE ReadCellCoordinate(theRefNum: INTEGER;
  154.                              VAR r: RowNumber;
  155.                              VAR c: ColumnNumber);
  156. { Reads a cell coordinate from a file }
  157.  
  158.     VAR
  159.         cellCoordinate:     Point;
  160.  
  161.     BEGIN
  162.     ReadBytes(theRefNum, SIZEOF(cellCoordinate), @cellCoordinate);
  163.     r := cellCoordinate.v;
  164.     c := cellCoordinate.h;
  165.     END;
  166.  
  167. {***************************************************************************************************
  168.      T C a l c A p p l i c a t i o n
  169. ***************************************************************************************************}
  170. {$S AInit}
  171.  
  172. PROCEDURE TCalcApplication.ICalcApplication(itsFileType: OSType);
  173.  
  174.     BEGIN
  175.     IApplication(itsFileType);
  176.  
  177.     gGeneralFormat.Style := FloatDecimal;
  178.     gGeneralFormat.digits := kValuePrecision;
  179.  
  180.     gDecimalFormat.Style := FixedDecimal;
  181.     gDecimalFormat.digits := 2;
  182.  
  183.     gNoDecimalFormat.Style := FixedDecimal;
  184.     gNoDecimalFormat.digits := 0;
  185.  
  186.     gScientificFormat.Style := FloatDecimal;
  187.     gScientificFormat.digits := 2;
  188.  
  189.     gNoFormat.Style := FixedDecimal;
  190.     gNoFormat.digits := - 1;
  191.  
  192.     gDefaultFormat.fJustification := kDefaultJustification;
  193.     gDefaultFormat.fStyle := General;
  194.     gDefaultFormat.fDigits := 0;
  195.     gDefaultFormat.fFontNumber := kCellFont;
  196.     gDefaultFormat.fFontSize := kCellFontSize;
  197.     gDefaultFormat.fFontStyle := [];
  198.  
  199.     gColumnSeparatorPattern := gray;
  200.     gRowSeparatorPattern := gray;
  201.  
  202.     { Suppress Linker dead-stripping of these classes }
  203.     IF gDeadStripSuppression THEN
  204.         BEGIN
  205.         IF Member(TObject(NIL), TCalcWindow) THEN;
  206.         IF Member(TObject(NIL), TCellsView) THEN;
  207.         IF Member(TObject(NIL), TRowsView) THEN;
  208.         IF Member(TObject(NIL), TColumnsView) THEN;
  209.         IF Member(TObject(NIL), TEntryView) THEN;
  210.         IF Member(TObject(NIL), TCoordView) THEN;
  211.         END;
  212.     END;
  213.  
  214. {--------------------------------------------------------------------------------------------------}
  215. {$S ADoCommand}
  216.  
  217. PROCEDURE TCalcApplication.AboutToLoseControl(convertClipboard: BOOLEAN); OVERRIDE;
  218. { Remove Edit menu buzzwords for incoming Desk Accessory }
  219.  
  220.     BEGIN
  221.     SetEditCmdName(cCut, cStandardCut);
  222.     SetEditCmdName(cCopy, cStandardCopy);
  223.     SetEditCmdName(cClear, cStandardClear);
  224.  
  225.     INHERITED AboutToLoseControl(convertClipboard);
  226.     END;
  227.  
  228. {--------------------------------------------------------------------------------------------------}
  229. {$S AOpen}
  230.  
  231. FUNCTION TCalcApplication.DoMakeDocument(itsCmdNumber: cmdNumber): TDocument;
  232.  
  233.     VAR
  234.         aCalcDocument:        TCalcDocument;
  235.         dimensions:         Rect;
  236.  
  237.     BEGIN
  238.     { Allocate and initialize the document}
  239.     NEW(aCalcDocument);
  240.     FailNIL(aCalcDocument);
  241.     SetRect(dimensions, 1, 1, kMaxColumns, kMaxRows);
  242.     aCalcDocument.ICalcDocument(dimensions);
  243.     DoMakeDocument := aCalcDocument;
  244.     END;
  245.  
  246. {--------------------------------------------------------------------------------------------------}
  247. {$S AClipboard}
  248.  
  249. FUNCTION TCalcApplication.MakeViewForAlienClipboard: TView; OVERRIDE;
  250.  { Launch a view to represent the data found in the Clipboard at
  251.    application start-up time, or when returning from an excursion
  252.    to MultiFinder, or when returning from a Desk Accessory.  This
  253.    creates a clipboard for 'CALC' scrap. }
  254.  
  255.     VAR
  256.         calcScrap:            Handle;
  257.         scrapOffset:        LONGINT;
  258.         clipDocument:        TCalcDocument;
  259.         clipView:            TCellsView;
  260.         scrapInfo:            ScrapInfoRecord;
  261.         r:                    RowNumber;
  262.         c:                    ColumnNumber;
  263.         i:                    INTEGER;
  264.         cellsRead:            INTEGER;
  265.         cellCoord:            Point;
  266.         offset:             LONGINT;
  267.         aRow:                TRow;
  268.         aColumn:            TColumn;
  269.         aCell:                TCell;
  270.         perm:                BOOLEAN;
  271.         fi:                 FailInfo;
  272.  
  273. {--------------------------------------------------------------------------------------------------}
  274.  
  275.     PROCEDURE HdlScrapFailure(error: OSErr;
  276.                               message: LONGINT);
  277.  
  278.         BEGIN
  279.         calcScrap := DisposeIfHandle(calcScrap);
  280.  
  281.         FreeIfObject(clipDocument);
  282.         clipDocument := NIL;
  283.         END;
  284.  
  285.     BEGIN
  286.     { Before doing anything else, make sure the scrap contains my type }
  287.     IF GetScrap(NIL, kCalcScrapType, offset) > 0 THEN
  288.         BEGIN
  289.         clipDocument := NIL;                            { so failure handler knows to free it }
  290.         calcScrap := NIL;
  291.  
  292.         CatchFailures(fi, HdlScrapFailure);
  293.  
  294.         calcScrap := NewPermHandle(0);
  295.         FailNIL(calcScrap);
  296.  
  297.         perm := PermAllocation(TRUE);
  298.         scrapOffset := GetScrap(calcScrap, kCalcScrapType, offset);
  299.         perm := PermAllocation(perm);
  300.  
  301.     { Only a negative result indicates an error--FailOSErr considers any non-zero result an error. }
  302.         IF scrapOffset < 0 THEN
  303.             FailOSErr(scrapOffset);
  304.         scrapOffset := 0;
  305.  
  306.         ReadScrap(calcScrap, scrapOffset, @scrapInfo, SIZEOF(scrapInfo));
  307.         FailMemError;
  308.         NEW(clipDocument);
  309.         FailNIL(clipDocument);
  310.         clipDocument.ICalcDocument(scrapInfo.selection);
  311.         clipDocument.DoInitialState;
  312.  
  313.         NEW(clipView);
  314.         FailNIL(clipView);
  315.         clipView.ICellsView(clipDocument, TRUE, NIL);
  316.         clipDocument.fCellsView := clipView;
  317.  
  318.         FOR r := 1 TO clipDocument.fNoOfRows DO
  319.             BEGIN
  320.             NEW(aRow);
  321.             aRow.ReadFromScrap(calcScrap, scrapOffset);
  322.             clipDocument.AddRow(aRow);
  323.             END;
  324.  
  325.         FOR c := 1 TO clipDocument.fNoOfColumns DO
  326.             BEGIN
  327.             NEW(aColumn);
  328.             aColumn.ReadFromScrap(calcScrap, scrapOffset);
  329.             clipDocument.AddColumn(aColumn);
  330.             END;
  331.  
  332.         cellsRead := 0;
  333.         FOR i := 1 TO scrapInfo.noOfCells DO
  334.             BEGIN
  335.             ReadScrap(calcScrap, scrapOffset, @cellCoord, SIZEOF(cellCoord));
  336.             aCell := clipDocument.GetCell(cellCoord.v, cellCoord.h);
  337.             aCell.ReadFromScrap(calcScrap, scrapOffset);
  338.             cellsRead := cellsRead + 1;
  339.             END;
  340.  
  341.         {$IFC qDebug}
  342.         IF gIntenseDebugging THEN
  343.             BEGIN
  344.             WRITELN('MakeViewForAlienClipboard: cellsRead=', cellsRead: 0, ', scrapInfo.noOfCells=',
  345.                     scrapInfo.noOfCells);
  346.             IF cellsRead <> scrapInfo.noOfCells THEN
  347.                 ProgramBreak('MakeViewForAlienClipboard: Wrong number of cells');
  348.             END;
  349.         {$ENDC}
  350.  
  351.         calcScrap := DisposeIfHandle(calcScrap);
  352.  
  353.         Success(fi);
  354.         MakeViewForAlienClipboard := clipView;
  355.         END
  356.     ELSE
  357.         MakeViewForAlienClipboard := INHERITED MakeViewForAlienClipboard;
  358.     END;
  359.  
  360. {***************************************************************************************************
  361.     T C a l c D o c u m e n t
  362. ***************************************************************************************************}
  363. {$S AOpen}
  364.  
  365. PROCEDURE TCalcDocument.ICalcDocument(dimensions: Rect);
  366.  
  367.     VAR
  368.         r:                    RowNumber;
  369.         c:                    ColumnNumber;
  370.         aRect:                Rect;
  371.  
  372.     BEGIN
  373.     IDocument(kFileType, kSignature, kUsesDataFork, NOT kUsesRsrcFork, NOT kDataOpen,
  374.               NOT kRsrcOpen);
  375.  
  376.     fSavePrintInfo := TRUE;                             { the 'print info' record of the
  377.                                                          fDocPrintHandler will be written out to
  378.                                                          the data fork }
  379.  
  380.     fDimensions := dimensions;
  381.     WITH dimensions DO
  382.         BEGIN
  383.         fRowOffset := top - 1;
  384.         fColumnOffset := left - 1;
  385.         fNoOfRows := bottom - top + 1;
  386.         fNoOfColumns := right - left + 1;
  387.         END;
  388.     fCalcMode := kCalcMode;
  389.     fSelectionType := NoSelection;
  390.  
  391.     fCellsView := NIL;
  392.     fRowsView := NIL;
  393.     fColumnsView := NIL;
  394.     fEntryView := NIL;
  395.     fCoordView := NIL;
  396.  
  397.     fEditRow := 0;
  398.     fEditColumn := 0;
  399.     fEditCell := NIL;
  400.  
  401.     { Initialize cells, rows and columns }
  402.     FOR r := 1 TO fNoOfRows DO
  403.         BEGIN
  404.         fRows[r] := NIL;
  405.         FOR c := 1 TO fNoOfColumns DO
  406.             BEGIN
  407.             fCells[r, c] := NIL;
  408.             END;
  409.         END;
  410.  
  411.     FOR c := 1 TO fNoOfColumns DO
  412.         fColumns[c] := NIL;
  413.  
  414.     SetRect(aRect, 1, 1, 1, 1);
  415.     fInUseBounds := aRect;
  416.     END;
  417.  
  418. {--------------------------------------------------------------------------------------------------}
  419. {$S AClose}
  420.  
  421. PROCEDURE TCalcDocument.Free;
  422.  
  423.     BEGIN
  424.     FreeData;
  425.  
  426.     INHERITED Free;
  427.     END;
  428.  
  429. {--------------------------------------------------------------------------------------------------}
  430. {$S ADoCommand}
  431.  
  432. PROCEDURE TCalcDocument.AddCell(theCell: TCell;
  433.                                 r: RowNumber;
  434.                                 c: ColumnNumber);
  435.  
  436.     VAR
  437.         aRect:                Rect;
  438.  
  439.     BEGIN
  440.     fCells[r, c] := theCell;
  441.     fAllocatedCells := fAllocatedCells + 1;
  442.  
  443.     SetRect(aRect, c, r, c, r);
  444.     {$Push} {$H-}
  445.     UnionRect(aRect, fInUseBounds, fInUseBounds);
  446.     {$Pop}
  447.  
  448.     WITH theCell DO
  449.         BEGIN
  450.         fCalcDocument := SELF;
  451.         fRow := r;
  452.         fColumn := c;
  453.         END;
  454.     END;
  455.  
  456. {--------------------------------------------------------------------------------------------------}
  457. {$S ADoCommand}
  458.  
  459. PROCEDURE TCalcDocument.AddColumn(theColumn: TColumn);
  460.  
  461.     BEGIN
  462.     fColumns[theColumn.fNumber] := theColumn;
  463.     fAllocatedColumns := fAllocatedColumns + 1;
  464.  
  465.     fInUseBounds.left := Min(fInUseBounds.left, theColumn.fNumber);
  466.     fInUseBounds.right := Max(fInUseBounds.right, theColumn.fNumber);
  467.     END;
  468.  
  469. {--------------------------------------------------------------------------------------------------}
  470. {$S ADoCommand}
  471.  
  472. PROCEDURE TCalcDocument.AddRow(theRow: TRow);
  473.  
  474.     BEGIN
  475.     fRows[theRow.fNumber] := theRow;
  476.     fAllocatedRows := fAllocatedRows + 1;
  477.  
  478.     fInUseBounds.top := Min(fInUseBounds.top, theRow.fNumber);
  479.     fInUseBounds.bottom := Max(fInUseBounds.bottom, theRow.fNumber);
  480.     END;
  481.  
  482. {--------------------------------------------------------------------------------------------------}
  483. {$S ARes}
  484.  
  485. FUNCTION TCalcDocument.CellExists(r: RowNumber;
  486.                                   c: ColumnNumber): BOOLEAN;
  487.  
  488.     BEGIN
  489.     CellExists := (r > 0) & (r <= kMaxRows) & (c > 0) & (c <= kMaxColumns) & (fCells[r, c] <> NIL) &
  490.                   (NOT fCells[r, c].fDeleted);
  491.     END;
  492.  
  493. {--------------------------------------------------------------------------------------------------}
  494. {$S ADoCommand}
  495.  
  496. FUNCTION TCalcDocument.CellInRange(r: INTEGER;
  497.                                    c: INTEGER;
  498.                                    range: Rect): BOOLEAN;
  499.  
  500.     BEGIN
  501.     WITH range DO
  502.         CellInRange := (r >= top) & (r <= bottom) & (c >= left) & (c <= right);
  503.     END;
  504.  
  505. {--------------------------------------------------------------------------------------------------}
  506. {$S ADoCommand}
  507.  
  508. FUNCTION TCalcDocument.ColumnExists(c: ColumnNumber): BOOLEAN;
  509.  
  510.     BEGIN
  511.     ColumnExists := (c > 0) & (c <= kMaxColumns) & (fColumns[c] <> NIL);
  512.     END;
  513.  
  514. {--------------------------------------------------------------------------------------------------}
  515. {$S ADoCommand}
  516.  
  517. PROCEDURE TCalcDocument.ConstrainToUsedCells(VAR cellRange: Rect);
  518.  { Given a range of cells, this returns the range of cells that fall
  519.    within the range of used cells.    This is used to optimize
  520.    performance so that we don't try to operate on cells that
  521.    we know have never been used (i.e. allocated). }
  522.  
  523.     BEGIN
  524.     WITH cellRange DO
  525.         BEGIN
  526.         top := Max(top, fInUseBounds.top);
  527.         left := Max(left, fInUseBounds.left);
  528.         bottom := Min(bottom, fInUseBounds.bottom);
  529.         right := Min(right, fInUseBounds.right);
  530.         END;
  531.     END;
  532.  
  533. {--------------------------------------------------------------------------------------------------}
  534. {$S ARes}
  535.  
  536. PROCEDURE TCalcDocument.DeleteCell(r: RowNumber;
  537.                                    c: ColumnNumber);
  538.  
  539.     VAR
  540.         theCell:            TCell;
  541.  
  542.     BEGIN
  543.     theCell := GetExistingCell(r, c);
  544.     IF theCell <> NIL THEN
  545.         BEGIN
  546.         theCell.SetDeleteState(TRUE);
  547.         fAllocatedCells := fAllocatedCells - 1;
  548.         IF theCell = fEditCell THEN
  549.             fEntryView.SetToString('');
  550.         END;
  551.     END;
  552.  
  553. {--------------------------------------------------------------------------------------------------}
  554. {$S AOpen}
  555.  
  556. PROCEDURE TCalcDocument.DoInitialState; OVERRIDE;
  557.  
  558.     BEGIN
  559.     fAllocatedCells := 0;
  560.     fAllocatedRows := 0;
  561.     fAllocatedColumns := 0;
  562.     END;
  563.  
  564. {--------------------------------------------------------------------------------------------------}
  565. {$S AOpen}
  566.  
  567. PROCEDURE TCalcDocument.DoMakeViews(forPrinting: BOOLEAN);
  568.  
  569.     VAR
  570.         aCalcWindow:        TCalcWindow;
  571.         aTEntryView:        TEntryView;
  572.         aCellsView:         TCellsView;
  573.         aColumnsView:        TColumnsView;
  574.         aRowsView:            TRowsView;
  575.         aCoordView:         TCoordView;
  576.         aRowScroller:        TSecondaryScroller;
  577.         aColumnScroller:    TSecondaryScroller;
  578.         aCalcScroller:        TPrimaryScroller;
  579.         aPrintHandler:        TCalcPrintHandler;
  580.  
  581.     PROCEDURE SetColumnWidths;
  582.  
  583.         VAR
  584.             c:                    ColumnNumber;
  585.             newWidth:            INTEGER;
  586.  
  587.         BEGIN
  588.         FOR c := 1 TO fNoOfColumns DO
  589.             IF fColumns[c] <> NIL THEN
  590.                 BEGIN
  591.                 newWidth := fColumns[c].fWidth;
  592.                 IF newWidth <> kCellWidth THEN
  593.                     BEGIN
  594.                     fCellsView.SetColWidth(c, 1, newWidth);
  595.                     fColumnsView.SetColWidth(c, 1, newWidth);
  596.                     END;
  597.                 END;
  598.         END;
  599.  
  600.     BEGIN
  601.     aCalcWindow := TCalcWindow(NewTemplateWindow(kCalcWindowType, SELF));
  602.     WITH aCalcWindow DO
  603.         BEGIN
  604.         aCellsView := TCellsView(FindSubView('CELL'));
  605.         aRowsView := TRowsView(FindSubView('ROWS'));
  606.         aColumnsView := TColumnsView(FindSubView('COLS'));
  607.         aTEntryView := TEntryView(FindSubView('ENTV'));
  608.         aCoordView := TCoordView(FindSubView('CORD'));
  609.         END;
  610.  
  611.     fCellsView := aCellsView;
  612.     fRowsView := aRowsView;
  613.     fColumnsView := aColumnsView;
  614.     fEntryView := aTEntryView;
  615.     fCoordView := aCoordView;
  616.  
  617.     IF NOT forPrinting THEN
  618.         BEGIN
  619.         aTEntryView.fText := NewPermHandle(0);
  620.         FailNIL(aTEntryView.fText);
  621.         aTEntryView.StuffText(aTEntryView.fText);        { Stuff the initial text in }
  622.         END;
  623.  
  624.     { Insert the entry view between the cell's view and its scroller in the target chain }
  625.     aCalcWindow.SetTarget(aCellsView);
  626.     aTEntryView.fNextHandler := aCellsView.fNextHandler;
  627.     aCellsView.fNextHandler := aTEntryView;
  628.  
  629.     { set up the cells view scroller to scroll the rows and columns too }
  630.     aCalcScroller := TPrimaryScroller(aCellsView.GetScroller(TRUE));
  631.     aCalcScroller.SetScrollParameters(kCellWidth, kCellHeight, TRUE, TRUE);
  632.  
  633.     aColumnScroller := TSecondaryScroller(aColumnsView.GetScroller(TRUE));
  634.     aColumnScroller.SetScrollParameters(kCellWidth, 0, TRUE, TRUE);
  635.  
  636.     aRowScroller := TSecondaryScroller(aRowsView.GetScroller(TRUE));
  637.     aRowScroller.SetScrollParameters(0, kCellHeight, TRUE, TRUE);
  638.  
  639.     aCalcScroller.AddSecondaryScroller(aRowScroller, kNotHDependent, kVDependent);
  640.     aCalcScroller.AddSecondaryScroller(aColumnScroller, kHDependent, kNotVDependent);
  641.  
  642.     NEW(aPrintHandler);
  643.     FailNIL(aPrintHandler);
  644.     aPrintHandler.IStdPrintHandler(SELF,                { its document }
  645.                                    aCellsView,            { its view }
  646.                                    NOT kSquareDots,     { does not have square dots }
  647.                                    NOT kFixedSize,        { horizontal page size is variable }
  648.                                    kFixedSize);         { vertical page size is fixed }
  649.     aPrintHandler.fMinimalMargins := FALSE;
  650.  
  651.     SetColumnWidths;                                    { get existing document's column widths }
  652.  
  653.     IF forPrinting THEN                                 { Finder printing }
  654.         aPrintHandler.RedoPageBreaks
  655.     ELSE
  656.         BEGIN
  657.         ShowReverted;                                    { display the views }
  658.  
  659.         fEditRow := 1;                                    { default cell to edit is A1 }
  660.         fEditColumn := 1;
  661.         SetEntry(fEditRow, fEditColumn);
  662.         fSelectionType := CellSelection;
  663.         fCellsView.SelectCell(GridCell($00010001), kDontExtend, kDontHighlight, kSelect);
  664.         END;
  665.     END;
  666.  
  667. {--------------------------------------------------------------------------------------------------}
  668. {$S ASelCommand}
  669.  
  670. FUNCTION TCalcDocument.DoMenuCommand(aCmdNumber: cmdNumber): TCommand;
  671.  
  672.     VAR
  673.         aColumnFormatter:    TColumnFormatter;
  674.  
  675.     BEGIN                                                { TCalcDocument.DoMenuCommand }
  676.     DoMenuCommand := NIL;
  677.     CASE aCmdNumber OF
  678.         cRecalculate:
  679.             DoRecalculate(kForceAutomatic, kSetDependents);
  680.         cAutoCalc:
  681.             BEGIN
  682.             fCalcMode := Automatic;
  683.             DoRecalculate(kForceAutomatic, kSetDependents);
  684.             END;
  685.         cManualCalc:
  686.             fCalcMode := Manual;
  687.  
  688.         cGeneral, cNoDecimal, cDecimal, cScientific, cSystemJustify, cForceLeftJustify, cRightJustify, cCenter:
  689.             BEGIN
  690.             NEW(aColumnFormatter);
  691.             FailNIL(aColumnFormatter);
  692.             aColumnFormatter.IFormatter(SELF, aCmdNumber);
  693.             DoMenuCommand := aColumnFormatter;
  694.             END;
  695.  
  696.         OTHERWISE
  697.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  698.     END;
  699.     END;
  700.  
  701. {--------------------------------------------------------------------------------------------------}
  702. {$S AWriteFile}
  703.  
  704. PROCEDURE TCalcDocument.DoNeedDiskSpace(VAR dataForkBytes, rsrcForkBytes: LONGINT);
  705.  
  706.     VAR
  707.         r:                    Rect;
  708.  
  709. {--------------------------------------------------------------------------------------------------}
  710.  
  711.     PROCEDURE AccountForCell(aCell: GridCell);
  712.  
  713.         BEGIN
  714.         dataForkBytes := dataForkBytes + GetCell(aCell.v, aCell.h).GetDiskSize(FALSE);
  715.         END;
  716.  
  717.     BEGIN
  718.     { get Print record requirements }
  719.     INHERITED DoNeedDiskSpace(dataForkBytes, rsrcForkBytes);
  720.  
  721.     dataForkBytes := dataForkBytes + SIZEOF(CalcDocDiskInfo) + SIZEOF(RowDiskInfo) *
  722.                      fAllocatedRows + SIZEOF(ColumnDiskInfo) * fAllocatedColumns;
  723.     r := fInUseBounds;
  724.     EachExistingCellDo(r, AccountForCell);
  725.  
  726.     END;
  727.  
  728. {--------------------------------------------------------------------------------------------------}
  729. {$S AReadFile}
  730.  
  731. PROCEDURE TCalcDocument.DoRead(aRefNum: INTEGER;
  732.                                rsrcExists, forPrinting: BOOLEAN);
  733.  
  734.     VAR
  735.         i:                    INTEGER;
  736.         noOfCells:            INTEGER;
  737.         noOfRows:            INTEGER;
  738.         noOfColumns:        INTEGER;
  739.         r:                    RowNumber;
  740.         c:                    ColumnNumber;
  741.         aCell:                TCell;
  742.         aRow:                TRow;
  743.         aColumn:            TColumn;
  744.         fi:                 FailInfo;
  745.  
  746. {--------------------------------------------------------------------------------------------------}
  747.  
  748.     PROCEDURE ReadDocInfo;
  749.  
  750.         VAR
  751.             theDocInfo:         CalcDocDiskInfo;
  752.  
  753.         BEGIN
  754.         ReadBytes(aRefNum, SIZEOF(theDocInfo), @theDocInfo);
  755.  
  756.         WITH theDocInfo DO
  757.             BEGIN
  758.             fDimensions := dimensions;
  759.             fCalcMode := calcMode;
  760.             noOfRows := allocatedRows;
  761.             noOfColumns := allocatedColumns;
  762.             fAllocatedCells := allocatedCells;
  763.             fSelectionType := NoSelection;
  764.             fEditRow := editRow;
  765.             fEditColumn := editColumn;
  766.             END;
  767.  
  768.         WITH fDimensions DO
  769.             BEGIN
  770.             fNoOfRows := bottom - top + 1;
  771.             fNoOfColumns := right - left + 1;
  772.             END;
  773.  
  774.   { Save the number of cells to be read, then set fAllocatedCells to
  775.     zero.  As each cell is read fAllocatedCells is incremented.
  776.     When we've finished, noOfCells must equal fAllocatedCells. }
  777.         noOfCells := fAllocatedCells;
  778.         DoInitialState;                                 { clear allocation counts }
  779.         END;
  780.  
  781. {--------------------------------------------------------------------------------------------------}
  782.  
  783.     PROCEDURE HdlReadFailure(error: OSErr;
  784.                              message: LONGINT);
  785.  
  786.         BEGIN
  787.         { Oh Boy are we in trouble }
  788.   { Need to set back rows and columns to reflect the number read in so
  789.     the freedata routine (which will eventually be called by other
  790.     failure handlers on the stack) won't try to free unallocated objects}
  791.         IF c = 0 THEN
  792.             BEGIN
  793.             { We died while reading the rows in}
  794.             fNoOfRows := r - 1;
  795.             fNoOfColumns := 0;
  796.             END
  797.         ELSE IF i = 0 THEN
  798.             BEGIN
  799.             { Died in the columns }
  800.             fNoOfColumns := c - 1;
  801.             END;
  802.         END;
  803.  
  804.     BEGIN                                                { DoRead }
  805.     CatchFailures(fi, HdlReadFailure);
  806.     INHERITED DoRead(aRefNum, rsrcExists, forPrinting);
  807.  
  808.     ReadDocInfo;                                        { Get info about the document }
  809.     r := 0; c := 0; i := 0;                             { Initialized so failure handler knows where
  810.                                                          we died }
  811.  
  812.     FOR i := 1 TO noOfRows DO                            { Get info about each row }
  813.         BEGIN
  814.         ReadBytes(aRefNum, SIZEOF(r), @r);
  815.         aRow := GetRow(r);
  816.         aRow.ReadFromDisk(aRefNum);
  817.         END;
  818.  
  819.     FOR i := 1 TO noOfColumns DO                        { Get info about each column }
  820.         BEGIN
  821.         ReadBytes(aRefNum, SIZEOF(c), @c);
  822.         aColumn := GetColumn(c);
  823.         aColumn.ReadFromDisk(aRefNum);
  824.         END;
  825.  
  826.     FOR i := 1 TO noOfCells DO                            { Read in the cells }
  827.         BEGIN
  828.         ReadCellCoordinate(aRefNum, r, c);
  829.         aCell := GetCell(r, c);
  830.         aCell.ReadFromDisk(aRefNum);
  831.         END;
  832.  
  833.     {$IFC qDebug}
  834.     IF gIntenseDebugging THEN
  835.         BEGIN
  836.         WRITELN('TCalcDocument.DoRead: noOfCells=', noOfCells);
  837.         IF noOfCells <> fAllocatedCells THEN
  838.             BEGIN
  839.             WRITELN('TCalcDocument.DoRead: Wrong number of cells.  noOfCells=', noOfCells,
  840.                     ', fAllocatedCells=', fAllocatedCells);
  841.             ProgramBreak('');
  842.             END;
  843.         END;
  844.     {$ENDC}
  845.  
  846.     Success(fi);
  847.     END;                                                { DoRead }
  848.  
  849. {--------------------------------------------------------------------------------------------------}
  850. {$S ADoCommand}
  851.  
  852. PROCEDURE TCalcDocument.DoRecalculate(forceAutomatic: BOOLEAN;
  853.                                       setDependents: BOOLEAN);
  854.  
  855.     VAR
  856.         r:                    Rect;
  857.  
  858. {--------------------------------------------------------------------------------------------------}
  859.  
  860.     PROCEDURE RecalcCell(aCell: GridCell);
  861.  
  862.         BEGIN
  863.         GetCell(aCell.v, aCell.h).Recalculate(forceAutomatic, setDependents);
  864.         END;
  865.  
  866. {--------------------------------------------------------------------------------------------------}
  867.  
  868.     PROCEDURE RecalcExistingCell(aCell: GridCell);
  869.  
  870.         VAR
  871.             theCell:            TCell;
  872.  
  873.         BEGIN
  874.         theCell := GetExistingCell(aCell.v, aCell.h);
  875.         IF theCell <> NIL THEN
  876.             theCell.Recalculate(forceAutomatic, setDependents);
  877.         END;
  878.  
  879.     BEGIN
  880.     IF IsAutoCalc | forceAutomatic THEN
  881.         BEGIN
  882.         r := fInUseBounds;
  883.         EachExistingCellDo(r, RecalcCell);
  884.         END
  885.     ELSE
  886.         fCellsView.EachSelectedCellDo(RecalcExistingCell);
  887.     SetChangeCount(Max(fChangeCount + 1, 1));            { enable Save - document may have changed }
  888.     END;
  889.  
  890. {--------------------------------------------------------------------------------------------------}
  891. {$S ARes}
  892.  
  893. PROCEDURE TCalcDocument.DoSetupMenus; OVERRIDE;
  894.  
  895.     VAR
  896.         justification:        INTEGER;
  897.         Style:                TypeOfStyle;
  898.         columnFormat:        FormatRecord;
  899.  
  900.     BEGIN
  901.  
  902.     INHERITED DoSetupMenus;
  903.  
  904.     Enable(cRecalculate, TRUE);
  905.     EnableCheck(cAutoCalc, TRUE, IsAutoCalc);
  906.     EnableCheck(cManualCalc, TRUE, fCalcMode = Manual);
  907.  
  908.     IF fColumnIsSelected THEN
  909.         BEGIN
  910.         IF ColumnExists(fEditColumn) THEN
  911.             columnFormat := GetColumn(fEditColumn).fFormat
  912.         ELSE
  913.             columnFormat := gDefaultFormat;
  914.         justification := columnFormat.fJustification;
  915.         Style := columnFormat.fStyle;
  916.  
  917.         EnableCheck(cSystemJustify, TRUE, justification = teJustSystem);
  918.         EnableCheck(cForceLeftJustify, TRUE, justification = teForceLeft);
  919.         EnableCheck(cRightJustify, TRUE, justification = TEJustRight);
  920.         EnableCheck(cCenter, TRUE, justification = TEJustCenter);
  921.  
  922.         EnableCheck(cGeneral, TRUE, Style = General);
  923.         EnableCheck(cDecimal, TRUE, Style = DecimalStyle);
  924.         EnableCheck(cNoDecimal, TRUE, Style = NoDecimal);
  925.         EnableCheck(cScientific, TRUE, Style = Scientific);
  926.         END
  927.     ELSE
  928.         BEGIN
  929.         Enable(cSystemJustify, FALSE);
  930.         Enable(cForceLeftJustify, FALSE);
  931.         Enable(cRightJustify, FALSE);
  932.         Enable(cCenter, FALSE);
  933.  
  934.         Enable(cGeneral, FALSE);
  935.         Enable(cDecimal, FALSE);
  936.         Enable(cNoDecimal, FALSE);
  937.         Enable(cScientific, FALSE);
  938.         END;
  939.  
  940.     END;
  941.  
  942. {--------------------------------------------------------------------------------------------------}
  943. {$S AWriteFile}
  944.  
  945. PROCEDURE TCalcDocument.DoWrite(aRefNum: INTEGER;
  946.                                 makingCopy: BOOLEAN);
  947.  
  948.     VAR
  949.         cellsWritten:        INTEGER;
  950.         r:                    Rect;
  951.  
  952. {--------------------------------------------------------------------------------------------------}
  953.  
  954.     PROCEDURE WriteDocInfo;
  955.  
  956.         VAR
  957.             theDocInfo:         CalcDocDiskInfo;
  958.  
  959.         BEGIN
  960.         WITH theDocInfo DO
  961.             BEGIN
  962.             dimensions := fDimensions;
  963.             calcMode := fCalcMode;
  964.             allocatedRows := fAllocatedRows;
  965.             allocatedColumns := fAllocatedColumns;
  966.             allocatedCells := fAllocatedCells;
  967.             selectionType := NoSelection;
  968.             editRow := fEditRow;
  969.             editColumn := fEditColumn;
  970.             END;
  971.         WriteBytes(aRefNum, SIZEOF(theDocInfo), @theDocInfo);
  972.         END;
  973.  
  974. {--------------------------------------------------------------------------------------------------}
  975.  
  976.     PROCEDURE WriteRow(aCell: GridCell);
  977.  
  978.         BEGIN
  979.         GetRow(aCell.v).WriteToDisk(aRefNum);
  980.         END;
  981.  
  982. {--------------------------------------------------------------------------------------------------}
  983.  
  984.     PROCEDURE WriteColumn(aCell: GridCell);
  985.  
  986.         VAR
  987.             theColumn:            TColumn;
  988.  
  989.         BEGIN
  990.         theColumn := GetColumn(aCell.h);
  991.         theColumn.fWidth := fColumnsView.GetColWidth(aCell.h);
  992.         theColumn.WriteToDisk(aRefNum);
  993.         END;
  994.  
  995. {--------------------------------------------------------------------------------------------------}
  996.  
  997.     PROCEDURE WriteCell(aCell: GridCell);
  998.  
  999.         BEGIN
  1000.         GetCell(aCell.v, aCell.h).WriteToDisk(aRefNum);
  1001.         cellsWritten := cellsWritten + 1;
  1002.         END;
  1003.  
  1004.     BEGIN
  1005.     INHERITED DoWrite(aRefNum, makingCopy);
  1006.  
  1007.     WriteDocInfo;                                        { Write info about the document }
  1008.  
  1009.     EachExistingRowDo(WriteRow);                        { Write info about each row }
  1010.     EachExistingColumnDo(WriteColumn);                    { Write info about each column }
  1011.  
  1012.     cellsWritten := 0;
  1013.     r := fInUseBounds;
  1014.     EachExistingCellDo(r, WriteCell);                    { Write out the cells }
  1015.  
  1016.     {$IFC qDebug}
  1017.     IF cellsWritten <> fAllocatedCells THEN
  1018.         ProgramBreak('DoWrite: Incorrect number of cells written');
  1019.     {$ENDC}
  1020.     END;
  1021.  
  1022. {--------------------------------------------------------------------------------------------------}
  1023. {$S ARes}
  1024.  
  1025. PROCEDURE TCalcDocument.EachExistingRowDo(PROCEDURE
  1026.                                           DoToCell(aCell: GridCell));
  1027. { Perform DoToCell for each ALLOCATED Row }
  1028.  
  1029.     VAR
  1030.         r:                    RowNumber;
  1031.         aCell:                GridCell;
  1032.         aRect:                Rect;
  1033.  
  1034.     BEGIN
  1035.     aRect := fInUseBounds;
  1036.     WITH aRect DO
  1037.         BEGIN
  1038.         FOR r := top TO bottom DO
  1039.             BEGIN
  1040.             IF RowExists(r) THEN
  1041.                 BEGIN
  1042.                 aCell.h := 1;
  1043.                 aCell.v := r;
  1044.                 DoToCell(aCell);
  1045.                 END;
  1046.             END;
  1047.         END;
  1048.     END;
  1049.  
  1050. {--------------------------------------------------------------------------------------------------}
  1051. {$S ARes}
  1052.  
  1053. PROCEDURE TCalcDocument.EachExistingColumnDo(PROCEDURE
  1054.                                              DoToCell(aCell: GridCell));
  1055. { Perform DoToCell for each ALLOCATED Column }
  1056.  
  1057.     VAR
  1058.         c:                    ColumnNumber;
  1059.         aCell:                GridCell;
  1060.         aRect:                Rect;
  1061.  
  1062.     BEGIN
  1063.     aRect := fInUseBounds;
  1064.     WITH aRect DO
  1065.         BEGIN
  1066.         FOR c := left TO right DO
  1067.             BEGIN
  1068.             IF ColumnExists(c) THEN
  1069.                 BEGIN
  1070.                 aCell.h := c;
  1071.                 aCell.v := 1;
  1072.                 DoToCell(aCell);
  1073.                 END;
  1074.             END;
  1075.         END;
  1076.     END;
  1077.  
  1078. {--------------------------------------------------------------------------------------------------}
  1079. {$S ARes}
  1080.  
  1081. PROCEDURE TCalcDocument.EachExistingCellDo(cellRange: Rect;
  1082.                                            PROCEDURE
  1083.                                            DoToCell(aCell: GridCell));
  1084. { Perform DoToCell for each ALLOCATED cell within a range of cells. }
  1085.  
  1086.     VAR
  1087.         r:                    RowNumber;
  1088.         c:                    ColumnNumber;
  1089.         aCell:                GridCell;
  1090.  
  1091.     BEGIN
  1092.     ConstrainToUsedCells(cellRange);
  1093.     WITH cellRange DO
  1094.         BEGIN
  1095.         FOR r := top TO bottom DO
  1096.             BEGIN
  1097.             FOR c := left TO right DO
  1098.                 BEGIN
  1099.                 IF CellExists(r, c) THEN
  1100.                     BEGIN
  1101.                     aCell.h := c;
  1102.                     aCell.v := r;
  1103.                     DoToCell(aCell);
  1104.                     END;
  1105.                 END;
  1106.             END;
  1107.         END;
  1108.     END;
  1109.  
  1110. {--------------------------------------------------------------------------------------------------}
  1111. {$S ADoCommand}
  1112.  
  1113. PROCEDURE TCalcDocument.EditCell;
  1114. { Change the formula of the cell being edited to the string in the entry view }
  1115.  
  1116.     VAR
  1117.         theString:            Str255;
  1118.  
  1119.     BEGIN
  1120.     fEntryView.GetAsString(theString);
  1121.     IF fEditCell = NIL THEN
  1122.         fEditCell := GetCell(fEditRow, fEditColumn);
  1123.     fEditCell.SetToString(theString);
  1124.     END;
  1125.  
  1126. {--------------------------------------------------------------------------------------------------}
  1127. {$S AFields}
  1128.  
  1129. PROCEDURE TCalcDocument.Fields(PROCEDURE DoToField(fieldName: Str255;
  1130.                                                    fieldAddr: Ptr;
  1131.                                                    fieldType: INTEGER)); OVERRIDE;
  1132.  
  1133.     VAR
  1134.         aString:            Str255;
  1135.  
  1136.     BEGIN
  1137.     DoToField('TCalcDocument', NIL, bClass);
  1138.     DoToField('fEditCell', @fEditCell, bObject);
  1139.     DoToField('fNoOfRows', @fNoOfRows, bInteger);
  1140.     DoToField('fNoOfColumns', @fNoOfColumns, bInteger);
  1141.     DoToField('fColumns', @fColumns, bObject);
  1142.     DoToField('fRows', @fRows, bObject);
  1143.     DoToField('fRowOffset', @fRowOffset, bInteger);
  1144.     DoToField('fColumnOffset', @fColumnOffset, bInteger);
  1145.     DoToField('fCellsView', @fCellsView, bObject);
  1146.     DoToField('fRowsView', @fRowsView, bObject);
  1147.     DoToField('fColumnsView', @fColumnsView, bObject);
  1148.     DoToField('fEntryView', @fEntryView, bObject);
  1149.     DoToField('fCoordView', @fCoordView, bObject);
  1150.     DoToField('fDimensions', @fDimensions, bRect);
  1151.     DoToField('fInUseBounds', @fInUseBounds, bRect);
  1152.     IF IsAutoCalc THEN
  1153.         aString := 'Automatic'
  1154.     ELSE
  1155.         aString := 'Manual';
  1156.     DoToField('fCalcMode', @aString, bString);
  1157.     DoToField('fAllocatedRows', @fAllocatedRows, bInteger);
  1158.     DoToField('fAllocatedColumns', @fAllocatedColumns, bInteger);
  1159.     DoToField('fAllocatedCells', @fAllocatedCells, bInteger);
  1160.     CASE fSelectionType OF
  1161.         NoSelection:
  1162.             aString := 'NoSelection';
  1163.         CellSelection:
  1164.             aString := 'CellSelection';
  1165.         RowSelection:
  1166.             aString := 'RowSelection';
  1167.         ColumnSelection:
  1168.             aString := 'ColumnSelection';
  1169.         AllSelection:
  1170.             aString := 'AllSelection';
  1171.     END;
  1172.     DoToField('fSelectionType', @aString, bString);
  1173.     DoToField('fEditRow', @fEditRow, bByte);
  1174.     DoToField('fEditColumn', @fEditColumn, bByte);
  1175.     INHERITED Fields(DoToField);
  1176.     END;
  1177.  
  1178. {--------------------------------------------------------------------------------------------------}
  1179. {$S ARes}
  1180.  
  1181. PROCEDURE TCalcDocument.FreeCell(theCell: TCell);
  1182.  
  1183.     PROCEDURE RemoveReferences(theObject: TObject);
  1184.     { remove any reference to cell that is about to be freed }
  1185.     VAR
  1186.         theCName:    MAName;
  1187.  
  1188.         BEGIN
  1189.         IF IsObject(theObject) & Member(theObject, TCell) THEN                     { may have been freed }
  1190.             BEGIN
  1191.             TCell(theObject).fReferences.Delete(theCell);
  1192.             END;
  1193.         END;
  1194.  
  1195.     BEGIN
  1196.     {$IFC qDebug}
  1197.     IF fCells[theCell.fRow, theCell.fColumn] <> theCell THEN
  1198.         ProgramBreak('TCalcDocument.FreeCell: Cell table inconsistent');
  1199.     {$ENDC}
  1200.  
  1201.     fCells[theCell.fRow, theCell.fColumn] := NIL;
  1202.     IF theCell.fDependents <> NIL THEN
  1203.         theCell.fDependents.Each(RemoveReferences);
  1204.  
  1205.     FreeIfObject(theCell);
  1206.     theCell := NIL;
  1207.     END;
  1208.  
  1209. {--------------------------------------------------------------------------------------------------}
  1210. {$S ARes}
  1211.  
  1212. PROCEDURE TCalcDocument.FreeData;
  1213.  
  1214.     VAR
  1215.         r:                    RowNumber;
  1216.         c:                    ColumnNumber;
  1217.         oldState:            BOOLEAN;
  1218.  
  1219.     BEGIN
  1220.     oldState := Lock(TRUE);                             { HLock(Handle(SELF)) }
  1221.     WITH fInUseBounds DO
  1222.         FOR r := top TO bottom DO
  1223.             FOR c := left TO right DO
  1224.                 IF fCells[r, c] <> NIL THEN
  1225.                 {$Push} {$H-}
  1226.                     FreeCell(fCells[r, c]);
  1227.     {$Pop}
  1228.  
  1229.     FOR r := 1 TO fNoOfRows DO
  1230.         BEGIN
  1231.         FreeIfObject(fRows[r]);                                { This is paranoia setting in}
  1232.         fRows[r] := NIL;
  1233.         END;
  1234.  
  1235.     FOR c := 1 TO fNoOfColumns DO
  1236.         BEGIN
  1237.         FreeIfObject(fColumns[c]);                            { I admit it - I'm paranoid}
  1238.         fColumns[c] := NIL;
  1239.         END;
  1240.  
  1241.     IF Lock(oldState) THEN;
  1242.     END;
  1243.  
  1244. {--------------------------------------------------------------------------------------------------}
  1245. {$S ADoCommand}
  1246.  
  1247. PROCEDURE TCalcDocument.FreeDeletedCells;
  1248. { Free each deleted cell. }
  1249.  
  1250.     VAR
  1251.         r:                    RowNumber;
  1252.         c:                    ColumnNumber;
  1253.         theCell:            TCell;
  1254.         cellRange:            Rect;
  1255.  
  1256.     BEGIN
  1257.     cellRange := fInUseBounds;
  1258.     WITH cellRange DO
  1259.         FOR r := top TO bottom DO
  1260.             FOR c := left TO right DO
  1261.                 BEGIN
  1262.                 theCell := fCells[r, c];
  1263.                 IF (theCell <> NIL) & theCell.fDeleted THEN
  1264.                     FreeCell(theCell);
  1265.                 END;
  1266.     END;
  1267.  
  1268. {--------------------------------------------------------------------------------------------------}
  1269. {$S ARes}
  1270.  
  1271. FUNCTION TCalcDocument.GetCell(r: RowNumber;
  1272.                                c: ColumnNumber): TCell;
  1273.  { Return the cell object for the given coordinates.  If a cell object
  1274.    doesn't already exist, create one. }
  1275.  
  1276.     VAR
  1277.         theCell:            TCell;
  1278.  
  1279.     BEGIN
  1280.     IF CellExists(r, c) THEN
  1281.         theCell := fCells[r, c]
  1282.     ELSE
  1283.         BEGIN
  1284.         NEW(theCell);
  1285.         FailNIL(theCell);
  1286.         theCell.ICell(SELF, r, c);
  1287.         AddCell(theCell, r, c);
  1288.         END;
  1289.  
  1290.     GetCell := theCell;
  1291.     END;
  1292.  
  1293. {--------------------------------------------------------------------------------------------------}
  1294. {$S ARes}
  1295.  
  1296. FUNCTION TCalcDocument.GetColumn(c: ColumnNumber): TColumn;
  1297.  
  1298.     VAR
  1299.         theColumn:            TColumn;
  1300.  
  1301.     BEGIN
  1302.     IF ColumnExists(c) THEN
  1303.         theColumn := fColumns[c]
  1304.     ELSE
  1305.         BEGIN
  1306.         NEW(theColumn);
  1307.         FailNIL(theColumn);
  1308.         theColumn.IColumn(c);
  1309.         AddColumn(theColumn);
  1310.         END;
  1311.  
  1312.     GetColumn := theColumn;
  1313.     END;
  1314.  
  1315. {--------------------------------------------------------------------------------------------------}
  1316. {$S ARes}
  1317.  
  1318. FUNCTION TCalcDocument.GetExistingCell(r: RowNumber;
  1319.                                        c: ColumnNumber): TCell;
  1320. { Like GetCell, only return NIL if the cell object doesn't exist }
  1321.  
  1322.     BEGIN
  1323.     IF CellExists(r, c) THEN
  1324.         GetExistingCell := fCells[r, c]
  1325.     ELSE
  1326.         GetExistingCell := NIL;
  1327.     END;
  1328.  
  1329. {--------------------------------------------------------------------------------------------------}
  1330. {$S ARes}
  1331.  
  1332. FUNCTION TCalcDocument.IsAutoCalc: BOOLEAN;
  1333.  
  1334.     BEGIN
  1335.     IsAutoCalc := fCalcMode = Automatic;
  1336.     END;
  1337.  
  1338. {--------------------------------------------------------------------------------------------------}
  1339. {$S ARes}
  1340.  
  1341. FUNCTION TCalcDocument.GetRow(r: RowNumber): TRow;
  1342.  
  1343.     VAR
  1344.         theRow:             TRow;
  1345.  
  1346.     BEGIN
  1347.     IF RowExists(r) THEN
  1348.         theRow := fRows[r]
  1349.     ELSE
  1350.         BEGIN
  1351.         NEW(theRow);
  1352.         FailNIL(theRow);
  1353.         theRow.IRow(r);
  1354.         AddRow(theRow);
  1355.         END;
  1356.  
  1357.     GetRow := theRow;
  1358.     END;
  1359.  
  1360. {--------------------------------------------------------------------------------------------------}
  1361. {$S ADoCommand}
  1362.  
  1363. FUNCTION TCalcDocument.RowExists(r: RowNumber): BOOLEAN;
  1364.  
  1365.     BEGIN
  1366.     RowExists := (r > 0) & (r <= kMaxRows) & (fRows[r] <> NIL);
  1367.     END;
  1368.  
  1369. {--------------------------------------------------------------------------------------------------}
  1370. {$S ADoCommand}
  1371.  
  1372. PROCEDURE TCalcDocument.SetEntry(r: RowNumber;
  1373.                                  c: ColumnNumber);
  1374. { Set the string in TEntryView to the formula in the cell }
  1375.  
  1376.     VAR
  1377.         theString:            Str255;
  1378.  
  1379.     BEGIN
  1380.     IF CellExists(r, c) THEN
  1381.         BEGIN
  1382.         fCells[r, c].GetAsString(theString);
  1383.         fEntryView.SetToString(theString);
  1384.         END
  1385.     ELSE
  1386.         fEntryView.SetToString('');
  1387.     END;
  1388.  
  1389. {--------------------------------------------------------------------------------------------------}
  1390. {$S ARes}
  1391.  
  1392. PROCEDURE TCalcDocument.UndeleteCell(r: RowNumber;
  1393.                                      c: ColumnNumber);
  1394.  
  1395.     BEGIN
  1396.     IF fCells[r, c] <> NIL THEN                         { can't use CellExists b/c it screens
  1397.                                                          deleted cells }
  1398.         BEGIN
  1399.         fCells[r, c].SetDeleteState(FALSE);
  1400.         fAllocatedCells := fAllocatedCells + 1;
  1401.         END;
  1402.     END;
  1403.  
  1404. {***************************************************************************************************
  1405.     T C a l c W i n d o w
  1406. ***************************************************************************************************}
  1407. {$S AOpen}
  1408.  
  1409. PROCEDURE TCalcWindow.IRes(itsDocument: TDocument;
  1410.                            itsSuperView: TView;
  1411.                            VAR itsParams: Ptr); OVERRIDE;
  1412.  
  1413.     VAR
  1414.         minSize:            Point;
  1415.  
  1416.     BEGIN
  1417.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  1418.     minSize.h := 284;
  1419.     minSize.v := 126;
  1420.     SetResizeLimits(minSize, gStdWSizeRect.botRight);
  1421.     END;
  1422.  
  1423. {--------------------------------------------------------------------------------------------------}
  1424. {$S ARes}
  1425.  
  1426. PROCEDURE TCalcWindow.Draw(area: Rect); OVERRIDE;
  1427.  
  1428.     BEGIN
  1429.     { draw the extra borders for the rows and columns views }
  1430.     PenNormal;
  1431.  
  1432.     { rows }
  1433.     MoveTo(0, 35);
  1434.     Line(kRowTitleWidth - 1, 0);
  1435.  
  1436.     MoveTo(0, 35 + kCellHeight - 1);
  1437.     Line(kRowTitleWidth - 1, 0);
  1438.  
  1439.     { columns }
  1440.     MoveTo(kRowTitleWidth - 1, 35);
  1441.     Line(0, kCellHeight - 1);
  1442.  
  1443.     INHERITED Draw(area);
  1444.     END;
  1445.  
  1446. {***************************************************************************************************
  1447.     T C e l l s V i e w
  1448. ***************************************************************************************************}
  1449. {$S AOpen}
  1450.  
  1451. PROCEDURE TCellsView.ICellsView(itsDocument: TCalcDocument;
  1452.                                 forClipboard: BOOLEAN;
  1453.                                 itsParent: TView);
  1454.  
  1455.     BEGIN
  1456.     fCalcDocument := itsDocument;
  1457.     fLastOptionKey := FALSE;                            { Used for DoSetCursor to the grabber hand }
  1458.  
  1459.     ITextGridView(itsDocument, itsParent, gZeroVPt, gZeroVPt, sizeVariable, sizeVariable,
  1460.                   itsDocument.fNoOfRows, itsDocument.fNoOfColumns, 0, kCellWidth, kAdorn, kAdorn,
  1461.                   0, 0, FALSE, gSystemStyle);
  1462.     fIdleFreq := Max(GetCaretTime DIV 2, 1);            { So we can trackCursor for the GrabberHand.
  1463.                                                          With MF 7.0 we could setup a VBL that
  1464.                                                          monitered the modifiers and called Wakeup
  1465.                                                          with our PID. Even better would be a call
  1466.                                                          that set the event manager so that an
  1467.                                                          event could be returned on modifier key
  1468.                                                          changes… oh, well. }
  1469.     END;
  1470.  
  1471. {--------------------------------------------------------------------------------------------------}
  1472. {$S AOpen}
  1473.  
  1474. PROCEDURE TCellsView.IRes(itsDocument: TDocument;
  1475.                           itsSuperView: TView;
  1476.                           VAR itsParams: Ptr); OVERRIDE;
  1477.  
  1478.     BEGIN
  1479.     fCalcDocument := TCalcDocument(itsDocument);
  1480.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  1481.     fIdleFreq := Max(GetCaretTime DIV 2, 1);            { So we can trackCursor for the GrabberHand.
  1482.                                                          With MF 7.0 we could setup a VBL that
  1483.                                                          monitered the modifiers and called Wakeup
  1484.                                                          with our PID. Even better would be a call
  1485.                                                          that set the event manager so that an
  1486.                                                          event could be returned on modifier key
  1487.                                                          changes… oh, well. }
  1488.     END;
  1489.  
  1490. {--------------------------------------------------------------------------------------------------}
  1491. {$S ARes}
  1492.  
  1493. PROCEDURE TCellsView.AdornRow(aRow: INTEGER;
  1494.                               area: Rect); OVERRIDE;
  1495.  
  1496.     BEGIN
  1497.     PenPat(gRowSeparatorPattern);
  1498.     PenSize(1, 1);
  1499.  
  1500.     MoveTo(area.left, area.bottom - 1);
  1501.     LineTo(area.right - 1, area.bottom - 1);
  1502.     END;
  1503.  
  1504. {--------------------------------------------------------------------------------------------------}
  1505. {$S ARes}
  1506.  
  1507. PROCEDURE TCellsView.AdornCol(aCol: INTEGER;
  1508.                               area: Rect); OVERRIDE;
  1509.  
  1510.     BEGIN
  1511.     PenPat(gColumnSeparatorPattern);
  1512.     PenSize(1, 1);
  1513.  
  1514.     MoveTo(area.right - 1, area.top);
  1515.     LineTo(area.right - 1, area.bottom - 1);
  1516.     END;
  1517.  
  1518. {--------------------------------------------------------------------------------------------------}
  1519. {$S AClipBoard}
  1520.  
  1521. FUNCTION TCellsView.ContainsClipType(aType: ResType): BOOLEAN;
  1522.  
  1523.     BEGIN
  1524.     ContainsClipType := aType = kCalcScrapType;
  1525.     END;
  1526.  
  1527. {--------------------------------------------------------------------------------------------------}
  1528. {$S ARes}
  1529.  
  1530. FUNCTION TCellsView.DoIdle(phase: IdlePhase): BOOLEAN;
  1531.  
  1532.     CONST
  1533.         kOptionKey            = $3A;
  1534.  
  1535.     VAR
  1536.         aKeyMap:            KeyMap;
  1537.  
  1538.     BEGIN
  1539.     DoIdle := FALSE;                                    { Didn't free myself }
  1540.  
  1541.     GetKeys(aKeyMap);
  1542.     IF fLastOptionKey <> aKeyMap[kOptionKey] THEN
  1543.         BEGIN
  1544.         fLastOptionKey := aKeyMap[kOptionKey];
  1545.         gApplication.InvalidateCursorRgn;                { Since we track the option key, we now need
  1546.                                                          to recalculate cursor rgn and SET the
  1547.                                                          cursor at next opportunity }
  1548.         END;
  1549.  
  1550.     END;
  1551.  
  1552. {--------------------------------------------------------------------------------------------------}
  1553. {$S ARes}
  1554.  
  1555. FUNCTION TCellsView.DoKeyCommand(Ch: CHAR;
  1556.                                  aKeyCode: INTEGER;
  1557.                                  VAR info: EventInfo): TCommand;
  1558.  { This view only handles arrow keys, tab, return and enter.  It assumes
  1559.    the other keys are handled by the entry view object. }
  1560.  
  1561.     VAR
  1562.         r:                    RowNumber;
  1563.         c:                    ColumnNumber;
  1564.         aCell:                GridCell;
  1565.         minToSee:            Point;
  1566.         aRect:                VRect;
  1567.  
  1568.     BEGIN
  1569.     DoKeyCommand := NIL;
  1570.  
  1571.     c := fCalcDocument.fEditColumn;
  1572.     r := fCalcDocument.fEditRow;
  1573.  
  1574.     CASE Ch OF
  1575.         chEnter:
  1576.             BEGIN
  1577.             { Stay on same cell }
  1578.             END;
  1579.         chTab, chRight:
  1580.             c := Min(c + 1, fCalcDocument.fNoOfColumns);
  1581.         chLeft:
  1582.             c := Max(c - 1, 1);
  1583.         chUp:
  1584.             r := Max(r - 1, 1);
  1585.         chReturn, chDown:
  1586.             r := Min(r + 1, fCalcDocument.fNoOfRows);
  1587.         OTHERWISE
  1588.             BEGIN
  1589.             DoKeyCommand := INHERITED DoKeyCommand(Ch, aKeyCode, info);
  1590.             fCalcDocument.fEditCell := fCalcDocument.GetCell(r, c);
  1591.             EXIT(DoKeyCommand);
  1592.             END;
  1593.     END;
  1594.  
  1595.     aCell.h := c;
  1596.     aCell.v := r;
  1597.  
  1598.     WITH fCalcDocument DO
  1599.         BEGIN
  1600.         SetChangeCount(Max(fChangeCount + 1, 1));        { enable Save - document may have changed }
  1601.  
  1602.         fEntryView.EditMode(FALSE);
  1603.         fColumnsView.SetEmptySelection(kHighlight);
  1604.         fRowsView.SetEmptySelection(kHighlight);
  1605.         fColumnIsSelected := FALSE;
  1606.  
  1607.         SelectCell(aCell, kDontExtend, kHighlight, kSelect);
  1608.         IF fEntryView.fTouched THEN
  1609.             DoRecalculate(NOT kForceAutomatic, kSetDependents);
  1610.         ScrollSelectionIntoView(TRUE);
  1611.  
  1612.         { fix the columns view }
  1613.         minToSee.h := fColumnsView.GetColWidth(aCell.h);
  1614.         minToSee.v := kCellHeight;
  1615.         aCell.v := 1;
  1616.         fColumnsView.CellToVRect(aCell, aRect);
  1617.         fColumnsView.RevealRect(aRect, minToSee, TRUE);
  1618.  
  1619.         { fix the rows view }
  1620.         minToSee.h := kCellWidth;
  1621.         minToSee.v := kCellHeight;
  1622.         aCell.v := r;
  1623.         aCell.h := 1;
  1624.         fRowsView.CellToVRect(aCell, aRect);
  1625.         fRowsView.RevealRect(aRect, minToSee, TRUE);
  1626.         END;
  1627.     END;
  1628.  
  1629. {--------------------------------------------------------------------------------------------------}
  1630. {$S ASelCommand}
  1631.  
  1632. FUNCTION TCellsView.DoMenuCommand(aCmdNumber: cmdNumber): TCommand; OVERRIDE;
  1633.  
  1634.     VAR
  1635.         aCellEditCommand:    TCellEditCommand;
  1636.         aCellPasteCommand:    TCellPasteCommand;
  1637.         cellsToSelect:        RgnHandle;
  1638.         aRect:                Rect;
  1639.  
  1640.     BEGIN
  1641.     CASE aCmdNumber OF
  1642.         cSelectAll:
  1643.             BEGIN
  1644.             aRect := fCalcDocument.fInUseBounds;
  1645.             WITH aRect DO
  1646.                 BEGIN
  1647.                 right := right + 1;
  1648.                 bottom := bottom + 1;
  1649.                 END;
  1650.             cellsToSelect := MakeNewRgn;
  1651.             RectRgn(cellsToSelect, aRect);
  1652.             SetSelection(cellsToSelect, kDontExtend, kHighlight, kSelect);
  1653.             DisposeRgn(cellsToSelect);
  1654.             WITH fCalcDocument DO
  1655.                 BEGIN
  1656.                 fSelectionType := AllSelection;
  1657.                 fRowsView.SetEmptySelection(kHighlight);
  1658.                 fColumnsView.SetEmptySelection(kHighlight);
  1659.                 fColumnIsSelected := FALSE;
  1660.                 END;
  1661.             DoMenuCommand := NIL;
  1662.             END;
  1663.  
  1664.         cCut, cCopy, cClear:
  1665.         { If user isn't editing this cell, he must want the cell itself. }
  1666.             IF NOT fCalcDocument.fEntryView.fTEditing THEN
  1667.                 BEGIN
  1668.                 NEW(aCellEditCommand);
  1669.                 FailNIL(aCellEditCommand);
  1670.                 aCellEditCommand.ICellEditCommand(fCalcDocument, aCmdNumber);
  1671.                 DoMenuCommand := aCellEditCommand;
  1672.                 END
  1673.             ELSE
  1674.                 BEGIN                                    { get ready for TextEdit operation }
  1675.                 WITH fCalcDocument DO
  1676.                     fEditCell := GetCell(fEditRow, fEditColumn);
  1677.                 DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1678.                 END;
  1679.  
  1680.         cPaste:
  1681.             IF gClipView.ContainsClipType(kCalcScrapType) THEN
  1682.                 BEGIN
  1683.                 NEW(aCellPasteCommand);
  1684.                 FailNIL(aCellPasteCommand);
  1685.                 aCellPasteCommand.ICellPasteCommand(fCalcDocument);
  1686.                 DoMenuCommand := aCellPasteCommand;
  1687.                 END
  1688.             ELSE
  1689.                 BEGIN                                    { paste text into entry view }
  1690.                 WITH fCalcDocument DO
  1691.                     BEGIN
  1692.                     fEditCell := GetCell(fEditRow, fEditColumn);
  1693.                     IF NOT fEntryView.fTEditing THEN
  1694.                         fEntryView.SetEditMode;         { prepare view for paste of text }
  1695.                     END;
  1696.                 DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1697.                 END;
  1698.  
  1699.         OTHERWISE
  1700.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  1701.     END;
  1702.     END;
  1703.  
  1704. {--------------------------------------------------------------------------------------------------}
  1705. {$S ASelCommand}
  1706.  
  1707. FUNCTION TCellsView.DoMouseCommand(VAR theMouse: Point;
  1708.                                    VAR info: EventInfo;
  1709.                                    VAR hysteresis: Point): TCommand; OVERRIDE;
  1710.  
  1711.     VAR
  1712.         aCellSelector:        TCalcSelectCommand;
  1713.         aColumnSizer:        TColumnSizer;
  1714.         aCell:                GridCell;
  1715.         whichPart:            GridViewPart;
  1716.         aRow:                INTEGER;
  1717.         aCol:                INTEGER;
  1718.         aGrabber:            TGrabberTracker;
  1719.  
  1720.     BEGIN
  1721.     DoMouseCommand := NIL;
  1722.     whichPart := IdentifyPoint(theMouse, aRow, aCol);
  1723.     aCell.h := aCol;
  1724.     aCell.v := aRow;
  1725.  
  1726.     IF info.theOptionKey THEN
  1727.         BEGIN
  1728.         NEW(aGrabber);
  1729.         FailNIL(aGrabber);
  1730.         aGrabber.IGrabberTracker(cNoCommand, fCalcDocument, SELF, GetScroller(FALSE));
  1731.         DoMouseCommand := aGrabber;
  1732.         END
  1733.     ELSE
  1734.         BEGIN
  1735.         CASE whichPart OF
  1736.             inCell:
  1737.                 BEGIN
  1738.                 NEW(aCellSelector);
  1739.                 FailNIL(aCellSelector);
  1740.                 aCellSelector.ICalcSelectCommand(fCalcDocument, SELF, info.theShiftKey,
  1741.                                                  info.theCmdKey);
  1742.                 DoMouseCommand := aCellSelector;
  1743.                 fCalcDocument.fSelectionType := CellSelection;
  1744.                 END;
  1745.  
  1746.             inColumn, inVertex:
  1747.                 BEGIN
  1748.                 IF aCol > 1 THEN
  1749.                     BEGIN
  1750.                     NEW(aColumnSizer);
  1751.                     FailNIL(aColumnSizer);
  1752.                     aColumnSizer.IColumnSizer(fCalcDocument, aCol - 1);
  1753.                     DoMouseCommand := aColumnSizer;
  1754.                     END;
  1755.                 END;
  1756.  
  1757.             OTHERWISE;
  1758.         END;
  1759.         fCalcDocument.fColumnsView.SetEmptySelection(kHighlight);
  1760.         fCalcDocument.fRowsView.SetEmptySelection(kHighlight);
  1761.         fCalcDocument.fColumnIsSelected := FALSE;
  1762.         fCalcDocument.fEditCell := NIL;
  1763.         END;
  1764.     END;
  1765.  
  1766. {--------------------------------------------------------------------------------------------------}
  1767. {$S ARes}
  1768.  
  1769. FUNCTION TCellsView.DoSetCursor(localPoint: Point;
  1770.                                 cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  1771.  
  1772.     CONST
  1773.         kOptionKey            = $3A;
  1774.  
  1775.     VAR
  1776.         aRow:                INTEGER;
  1777.         aCol:                INTEGER;
  1778.         aKeyMap:            KeyMap;
  1779.         cellsExtent:        VRect;
  1780.         cellsQDExtent, columnQDExtent: Rect;
  1781.  
  1782.     BEGIN
  1783.     DoSetCursor := FALSE;
  1784.  
  1785.     GetKeys(aKeyMap);
  1786.  
  1787.     { We may have been called from a mouse-moved.  Be kind to the DoIdle }
  1788.     fLastOptionKey := aKeyMap[kOptionKey];
  1789.  
  1790.     IF fLastOptionKey THEN
  1791.         BEGIN
  1792.         DoSetCursor := TRUE;
  1793.         SetCursor(GetCursor(kGrabberHand)^^);
  1794.         GetQDExtent(cellsQDExtent);
  1795.         RectRgn(cursorRgn, cellsQDExtent);
  1796.         END
  1797.     ELSE
  1798.         CASE IdentifyPoint(localPoint, aRow, aCol) OF
  1799.             badChoice: ;
  1800.             inColumn, inVertex:
  1801.                 IF aCol > 1 THEN
  1802.                     BEGIN
  1803.                     DoSetCursor := TRUE;
  1804.                     SetCursor(GetCursor(kColumnSizingCursor)^^);
  1805.                     ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  1806.                     ViewToQDRect(cellsExtent, cellsQDExtent);
  1807.                     columnQDExtent := cellsQDExtent;
  1808.  
  1809.                     { Which edge is the mouse closer to? }
  1810.                     IF abs(columnQDExtent.right - localPoint.h) < abs(columnQDExtent.left -
  1811.                                                                       localPoint.h) THEN
  1812.                         columnQDExtent.left := columnQDExtent.right;
  1813.  
  1814.                     columnQDExtent.left := columnQDExtent.left - fColInset DIV 2;
  1815.                     columnQDExtent.right := columnQDExtent.left + fColInset;
  1816.                     RectRgn(cursorRgn, columnQDExtent);
  1817.                     END;
  1818.             inRow, inCell:
  1819.                 BEGIN
  1820.                 DoSetCursor := TRUE;
  1821.                 SetCursor(GetCursor(plusCursor)^^);
  1822.                 ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  1823.                 InsetVRect(cellsExtent, fColInset DIV 2, 0); { Account for the column resizer }
  1824.                 ViewToQDRect(cellsExtent, cellsQDExtent);
  1825.                 RectRgn(cursorRgn, cellsQDExtent);
  1826.                 END;
  1827.         END;
  1828.     END;
  1829.  
  1830. {--------------------------------------------------------------------------------------------------}
  1831. {$S ARes}
  1832.  
  1833. PROCEDURE TCellsView.DoSetupMenus; OVERRIDE;
  1834.  
  1835.     VAR
  1836.         selection:            TypeOfSelection;
  1837.  
  1838.     BEGIN
  1839.     INHERITED DoSetupMenus;
  1840.  
  1841.     { If user isn't editing, then assume edit commands refer to cells }
  1842.     IF NOT fCalcDocument.fEntryView.fTEditing THEN
  1843.         BEGIN
  1844.         SetEditCmdName(cCut, cCutCells);
  1845.         SetEditCmdName(cCopy, cCopyCells);
  1846.         SetEditCmdName(cClear, cClearCells);
  1847.  
  1848.         CanPaste(kCalcScrapType);
  1849.         END;
  1850.  
  1851.     selection := fCalcDocument.fSelectionType;
  1852.     Enable(cCut, selection <> NoSelection);
  1853.     Enable(cCopy, selection <> NoSelection);
  1854.     Enable(cClear, selection <> NoSelection);
  1855.     Enable(cSelectAll, TRUE);
  1856.     END;
  1857.  
  1858. {--------------------------------------------------------------------------------------------------}
  1859. {$S ARes}
  1860.  
  1861. PROCEDURE TCellsView.DrawCell(aCell: GridCell;
  1862.                               aQDRect: Rect); OVERRIDE;
  1863.  
  1864.     VAR
  1865.         theCell:            TCell;
  1866.         theString:            Str255;
  1867.  
  1868.     BEGIN
  1869.     theCell := fCalcDocument.GetExistingCell(aCell.v, aCell.h);
  1870.     IF (theCell <> NIL) THEN
  1871.         WITH theCell DO
  1872.             BEGIN
  1873.             GetValueAsString(theString);
  1874.             SmartDrawString(theString, aQDRect,
  1875.                             fCalcDocument.GetColumn(aCell.h).fFormat.fJustification);
  1876.             END;
  1877.  
  1878.     END;
  1879.  
  1880. {--------------------------------------------------------------------------------------------------}
  1881. {$S AFields}
  1882.  
  1883. PROCEDURE TCellsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  1884.                                                 fieldAddr: Ptr;
  1885.                                                 fieldType: INTEGER)); OVERRIDE;
  1886.  
  1887.     BEGIN
  1888.     DoToField('TCellsView', NIL, bClass);
  1889.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  1890.     INHERITED Fields(DoToField);
  1891.     END;
  1892.  
  1893. {--------------------------------------------------------------------------------------------------}
  1894. {$S ADoCommand}
  1895.  
  1896. PROCEDURE TCellsView.GetVisibleCells(VAR visibleCells: Rect);
  1897.  
  1898.     VAR
  1899.         visibleRect:        Rect;
  1900.         visibleVRect:        VRect;
  1901.         topLeftVPoint:        VPoint;
  1902.  
  1903.     BEGIN
  1904.     IF Focus THEN;                                        { appease QDToViewRect }
  1905.     GetVisibleRect(visibleRect);
  1906.     topLeftVPoint := GetScroller(TRUE).fTranslation;
  1907.     visibleRect.topLeft := ViewToQDPt(topLeftVPoint);
  1908.     QDToViewRect(visibleRect, visibleVRect);
  1909.     visibleCells.topLeft := VPointToCell(visibleVRect.topLeft);
  1910.     visibleCells.botRight := VPointToCell(visibleVRect.botRight);
  1911.     END;
  1912.  
  1913. {--------------------------------------------------------------------------------------------------}
  1914. {$S ADoCommand}
  1915.  
  1916. FUNCTION TCellsView.IsCellVisible(aCell: GridCell): BOOLEAN;
  1917.  
  1918.     VAR
  1919.         visibleCells:        Rect;
  1920.  
  1921.     BEGIN
  1922.     GetVisibleCells(visibleCells);
  1923.     IsCellVisible := PtInRect(aCell, visibleCells);     { ??? use fCalcDocument.CellInRange }
  1924.     END;
  1925.  
  1926. {--------------------------------------------------------------------------------------------------}
  1927. {$S ADoCommand}
  1928.  
  1929. PROCEDURE TCellsView.PositionAtCell(aCell: GridCell);
  1930.  
  1931.     VAR
  1932.         aRect:                VRect;
  1933.         minToSee:            Point;
  1934.         r:                    INTEGER;
  1935.  
  1936.     BEGIN
  1937.     { position the cells view first }
  1938.     CellToVRect(aCell, aRect);
  1939.     WITH aRect DO
  1940.         SetPt(minToSee, right - left, bottom - top);
  1941.     RevealRect(aRect, minToSee, TRUE);
  1942.  
  1943.     WITH fCalcDocument DO
  1944.         BEGIN
  1945.         { fix up the columns view }
  1946.         r := aCell.v;
  1947.         minToSee.h := fColumnsView.GetColWidth(aCell.h);
  1948.         minToSee.v := kCellHeight;
  1949.         aCell.v := 1;
  1950.         fColumnsView.CellToVRect(aCell, aRect);
  1951.         fColumnsView.RevealRect(aRect, minToSee, TRUE);
  1952.  
  1953.         { fix up the rows view }
  1954.         minToSee.h := kCellWidth;
  1955.         minToSee.v := kCellHeight;
  1956.         aCell.v := r;
  1957.         aCell.h := 1;
  1958.         fRowsView.CellToVRect(aCell, aRect);
  1959.         fRowsView.RevealRect(aRect, minToSee, TRUE);
  1960.         END;
  1961.     END;
  1962.  
  1963. {--------------------------------------------------------------------------------------------------}
  1964. {$S ADoCommand}
  1965.  
  1966. PROCEDURE TCellsView.ReSelect(cellRegion: RgnHandle);
  1967.  
  1968.     VAR
  1969.         aCell:                GridCell;
  1970.  
  1971.     BEGIN
  1972.     aCell := cellRegion^^.rgnBBox.topLeft;
  1973.     IF NOT IsCellVisible(aCell) THEN
  1974.         PositionAtCell(aCell);                            { position cellRegion at top left of grid }
  1975.  
  1976.     IF NOT EqualRect(cellRegion^^.rgnBBox, fSelections^^.rgnBBox) THEN
  1977.         BEGIN
  1978.         WITH fCalcDocument DO
  1979.             BEGIN
  1980.             fColumnsView.SetEmptySelection(kHighlight);
  1981.             fRowsView.SetEmptySelection(kHighlight);
  1982.             fColumnIsSelected := FALSE;
  1983.             END;
  1984.         SetSelection(cellRegion, kDontExtend, kHighlight, kSelect);
  1985.         END;
  1986.     END;
  1987.  
  1988. {--------------------------------------------------------------------------------------------------}
  1989. {$S ADoCommand}
  1990.  
  1991. PROCEDURE TCellsView.ReSelectCell(aCell: GridCell);
  1992.  
  1993.     VAR
  1994.         cellRect:            Rect;
  1995.  
  1996.     BEGIN
  1997.     IF NOT IsCellVisible(aCell) THEN
  1998.         PositionAtCell(aCell);                            { position aCell at top left of grid }
  1999.  
  2000.     WITH aCell DO
  2001.         SetRect(cellRect, h, v, h + 1, v + 1);
  2002.     IF NOT EqualRect(cellRect, fSelections^^.rgnBBox) THEN
  2003.         BEGIN
  2004.         WITH fCalcDocument DO
  2005.             BEGIN
  2006.             fColumnsView.SetEmptySelection(kHighlight);
  2007.             fRowsView.SetEmptySelection(kHighlight);
  2008.             fColumnIsSelected := FALSE;
  2009.             END;
  2010.         SelectCell(aCell, kDontExtend, kHighlight, kSelect);
  2011.         END;
  2012.     END;
  2013.  
  2014. {--------------------------------------------------------------------------------------------------}
  2015. {$S ADoCommand}
  2016.  
  2017. PROCEDURE TCellsView.ScrollSelectionIntoView(redraw: BOOLEAN); OVERRIDE;
  2018.  
  2019.     VAR
  2020.         topLeftRect:        VRect;
  2021.         minToSee:            Point;
  2022.  
  2023.     BEGIN
  2024.     IF NOT (EmptyRgn(fSelections)) THEN
  2025.         BEGIN
  2026.         CellToVRect(fSelections^^.rgnBBox.topLeft, topLeftRect);
  2027.         WITH topLeftRect DO
  2028.             SetPt(minToSee, right - left, bottom - top);
  2029.         RevealRect(topLeftRect, minToSee, redraw);
  2030.         END;
  2031.     END;
  2032.  
  2033. {--------------------------------------------------------------------------------------------------}
  2034. {$S ADoCommand}
  2035.  
  2036. PROCEDURE TCellsView.SetCell(aCell: GridCell);
  2037.  
  2038.     BEGIN
  2039.     fCalcDocument.EditCell;                             { cell formula := string in entry view }
  2040.     InvalidateCell(aCell);                                { redraw the cell }
  2041.     END;
  2042.  
  2043. {--------------------------------------------------------------------------------------------------}
  2044. {$S ADoCommand}
  2045.  
  2046. PROCEDURE TCellsView.SetSelection(cellsToSelect: RgnHandle;
  2047.                                   extendSelection, highlight, select: BOOLEAN); OVERRIDE;
  2048.  
  2049.     VAR
  2050.         aQDRect:            Rect;
  2051.  
  2052.     BEGIN
  2053.     WITH fCalcDocument DO
  2054.         BEGIN
  2055.         INHERITED SetSelection(cellsToSelect, extendSelection, highlight, select);
  2056.  
  2057.         IF fEntryView.fTouched THEN                     { "commit" last cell }
  2058.             BEGIN
  2059.             EditCell;                                    { change fEditCell's formula to the string
  2060.                                                          in fEntryView }
  2061.             fEntryView.SetToString('');
  2062.             END;
  2063.  
  2064.         IF NOT extendSelection & (cellsToSelect^^.rgnBBox.top <> 0) &
  2065.            (cellsToSelect^^.rgnBBox.left <> 0) THEN
  2066.             BEGIN
  2067.             fEditColumn := cellsToSelect^^.rgnBBox.left;
  2068.             fEditRow := cellsToSelect^^.rgnBBox.top;
  2069.             fEditCell := fCells[fEditRow, fEditColumn];
  2070.  
  2071.             IF fCoordView.Focus THEN
  2072.                 BEGIN
  2073.                 fCoordView.GetQDExtent(aQDRect);
  2074.                 fCoordView.InvalidRect(aQDRect);
  2075.                 END;
  2076.             END;
  2077.  
  2078.         SetEntry(fEditRow, fEditColumn);                { set entry view contents to new cell }
  2079.         END;
  2080.     END;
  2081.  
  2082. {--------------------------------------------------------------------------------------------------}
  2083. {$S AClipBoard}
  2084.  
  2085. PROCEDURE TCellsView.WriteCalcScrap(calcScrap: Handle);
  2086.  
  2087.     VAR
  2088.         scrapOffset:        LONGINT;
  2089.         scrapInfo:            ScrapInfoRecord;
  2090.         cellsWritten:        INTEGER;
  2091.         i:                    INTEGER;
  2092.         r:                    Rect;
  2093.  
  2094. {--------------------------------------------------------------------------------------------------}
  2095.  
  2096.     PROCEDURE WriteCellToScrap(aCell: GridCell);
  2097.  
  2098.         BEGIN
  2099.         WITH fCalcDocument.GetCell(aCell.v, aCell.h) DO
  2100.             WriteToScrap(calcScrap, scrapOffset);
  2101.         cellsWritten := cellsWritten + 1;
  2102.         END;
  2103.  
  2104.     BEGIN
  2105.     SetHandleSize(calcScrap, 0);
  2106.     scrapOffset := 0;
  2107.  
  2108.     scrapInfo.selection.top := 1;
  2109.     scrapInfo.selection.left := 1;
  2110.     scrapInfo.selection.bottom := fCalcDocument.fNoOfRows;
  2111.     scrapInfo.selection.right := fCalcDocument.fNoOfColumns;
  2112.     scrapInfo.noOfCells := fCalcDocument.fAllocatedCells;
  2113.     WriteScrap(calcScrap, scrapOffset, @scrapInfo, SIZEOF(scrapInfo));
  2114.  
  2115.     cellsWritten := 0;
  2116.     WITH fCalcDocument DO
  2117.         BEGIN
  2118.         FOR i := 1 TO fCalcDocument.fNoOfRows DO
  2119.             BEGIN
  2120.             WITH fCalcDocument.GetRow(i) DO
  2121.                 WriteToScrap(calcScrap, scrapOffset);
  2122.             END;
  2123.  
  2124.         FOR i := 1 TO fCalcDocument.fNoOfColumns DO
  2125.             BEGIN
  2126.             WITH fCalcDocument.GetColumn(i) DO
  2127.                 WriteToScrap(calcScrap, scrapOffset);
  2128.             END;
  2129.         r := fCalcDocument.fInUseBounds;
  2130.         EachExistingCellDo(r, WriteCellToScrap);
  2131.         END;
  2132.  
  2133.     {$IFC qDebug}
  2134.     WRITELN('WriteCalcScrap: Number of cells written: ', cellsWritten: 0);
  2135.     IF cellsWritten <> scrapInfo.noOfCells THEN
  2136.         BEGIN
  2137.         WRITELN('WriteCalcScrap: Incorrect number of cells written.');
  2138.         WRITELN('     Should be ', scrapInfo.noOfCells: 0, ', was ', cellsWritten: 0);
  2139.         ProgramBreak('');
  2140.         END;
  2141.     {$ENDC}
  2142.  
  2143.     END;
  2144.  
  2145. {--------------------------------------------------------------------------------------------------}
  2146. {$S AClipBoard}
  2147.  
  2148. PROCEDURE TCellsView.WriteTextScrap(textScrap: Handle);
  2149.  
  2150.     VAR
  2151.         r:                    RowNumber;
  2152.         c:                    ColumnNumber;
  2153.         theText:            Str255;
  2154.         scrapOffset:        LONGINT;
  2155.         savedPort:            GrafPtr;
  2156.  
  2157.     BEGIN
  2158.     GetPort(savedPort);                                 { Use work port because GetValueAsString }
  2159.     SetPort(gWorkPort);                                 { …sets the current port's font }
  2160.  
  2161.     SetHandleSize(textScrap, 0);
  2162.     scrapOffset := 0;
  2163.  
  2164.     FOR r := 1 TO fCalcDocument.fNoOfRows DO
  2165.         BEGIN
  2166.         FOR c := 1 TO fCalcDocument.fNoOfColumns DO
  2167.             BEGIN
  2168.             IF fCalcDocument.CellExists(r, c) THEN
  2169.                 fCalcDocument.GetCell(r, c).GetValueAsString(theText)
  2170.             ELSE
  2171.                 theText := '';
  2172.             IF c > 1 THEN
  2173.                 theText := CONCAT(chTab, theText);
  2174.             WriteScrap(textScrap, scrapOffset, POINTER(ORD4(@theText) + 1), LENGTH(theText));
  2175.             END;
  2176.         theText := chReturn;
  2177.         WriteScrap(textScrap, scrapOffset, POINTER(ORD4(@theText) + 1), LENGTH(theText));
  2178.         END;
  2179.  
  2180.     SetPort(savedPort);
  2181.     END;
  2182.  
  2183. {--------------------------------------------------------------------------------------------------}
  2184. {$S AClipBoard}
  2185.  
  2186. PROCEDURE TCellsView.WriteToDeskScrap; OVERRIDE;
  2187.  
  2188.     VAR
  2189.         textScrap:            Handle;
  2190.         calcScrap:            Handle;
  2191.         err:                OSErr;
  2192.  
  2193.     BEGIN
  2194.     textScrap := NewPermHandle(0);
  2195.     FailNIL(textScrap);
  2196.     WriteTextScrap(textScrap);
  2197.     err := PutDeskScrapData(kTextScrapType, textScrap);
  2198.     textScrap := DisposeIfHandle(textScrap);
  2199.  
  2200.     FailOSErr(err);
  2201.  
  2202.     calcScrap := NewPermHandle(0);
  2203.     FailNIL(calcScrap);
  2204.     WriteCalcScrap(calcScrap);
  2205.     err := PutDeskScrapData(kCalcScrapType, calcScrap);
  2206.     calcScrap := DisposeIfHandle(calcScrap);
  2207.  
  2208.     FailOSErr(err);
  2209.     END;
  2210.  
  2211. {--------------------------------------------------------------------------------------------------}
  2212. {$S ANonRes}
  2213.  
  2214. FUNCTION TCellsView.DoBreakFollowing(vhs: VHSelect;
  2215.                                      prevBreak: VCoordinate;
  2216.                                      VAR Automatic: BOOLEAN): VCoordinate; OVERRIDE;
  2217. { Determines where page breaks occur for printing. }
  2218.  
  2219.     VAR
  2220.         thisBreak:            VCoordinate;
  2221.         rowsPerPage:        INTEGER;
  2222.         totalWidth:         INTEGER;
  2223.         width:                INTEGER;
  2224.         pageWidth:            INTEGER;
  2225.         extentRect:         VRect;
  2226.         firstCol:            ColumnNumber;
  2227.         c:                    ColumnNumber;
  2228.  
  2229.     FUNCTION ColumnAtCoord(loc: VCoordinate): INTEGER;
  2230.  
  2231.         BEGIN
  2232.         ColumnAtCoord := 1;
  2233.         IF loc = 0 THEN
  2234.             EXIT(ColumnAtCoord);
  2235.  
  2236.         c := 0;
  2237.         width := 0;
  2238.         REPEAT
  2239.             c := c + 1;
  2240.             width := width + GetColWidth(c);
  2241.         UNTIL width >= loc;
  2242.         ColumnAtCoord := c + 1;
  2243.         END;
  2244.  
  2245.     BEGIN
  2246.     GetExtent(extentRect);
  2247.     CASE vhs OF
  2248.         h:
  2249.             BEGIN
  2250.             rowsPerPage := fPrintHandler.fViewPerPage.v DIV kCellHeight;
  2251.             thisBreak := prevBreak + (rowsPerPage * kCellHeight);
  2252.             END;
  2253.         v:
  2254.             BEGIN
  2255.             pageWidth := fPrintHandler.fViewPerPage.h;
  2256.             totalWidth := 0;
  2257.             firstCol := ColumnAtCoord(prevBreak);
  2258.             FOR c := firstCol TO fCalcDocument.fNoOfColumns DO
  2259.                 BEGIN
  2260.                 width := GetColWidth(c);
  2261.                 IF totalWidth + width <= pageWidth THEN
  2262.                     totalWidth := totalWidth + width
  2263.                 ELSE
  2264.                     BEGIN
  2265.                     thisBreak := prevBreak + totalWidth;
  2266.                     LEAVE;
  2267.                     END;
  2268.                 END;
  2269.             IF thisBreak = prevBreak THEN                { Prevent ∞ loop resizing a far-right column
  2270.                                                          (L.T.!) }
  2271.                 thisBreak := extentRect.right;
  2272.             END;
  2273.     END;
  2274.     thisBreak := Min(thisBreak, extentRect.botRight.vh[gOrthogonal[vhs]]);
  2275.  
  2276.     {$IFC qDebug}
  2277.     IF (thisBreak <= prevBreak) | gDebugPrinting THEN
  2278.         BEGIN
  2279.         WRITE('TCellsView.DoBreakFollowing: prevBreak=');
  2280.         IF vhs = v THEN
  2281.             WRITELN('[v]', prevBreak, ', thisBreak=[v]', thisBreak)
  2282.         ELSE
  2283.             WRITELN('[h]', prevBreak, ', thisBreak=[h]', thisBreak);
  2284.  
  2285.         IF thisBreak <= prevBreak THEN
  2286.             ProgramBreak('thisBreak <= prevBreak');
  2287.         END;
  2288.     {$ENDC}
  2289.  
  2290.     DoBreakFollowing := thisBreak;
  2291.     END;
  2292.  
  2293. {--------------------------------------------------------------------------------------------------}
  2294. {$IFC qDebug}
  2295. {$S ANonRes}
  2296.  
  2297. PROCEDURE TCellsView.DoDrawPageBreak(vhs: VHSelect;
  2298.                                      whichBreak: INTEGER;
  2299.                                      loc: VCoordinate;
  2300.                                      Automatic: BOOLEAN); OVERRIDE;
  2301.  
  2302.     VAR
  2303.         vPt:                VPoint;
  2304.         qdStartPt:            Point;
  2305.         qdEndPt:            Point;
  2306.  
  2307.     BEGIN
  2308.     IF gDebugPrinting THEN
  2309.         BEGIN
  2310.         vPt.vh[gOrthogonal[vhs]] := loc;
  2311.         vPt.vh[vhs] := 0;
  2312.         qdStartPt := ViewToQDPt(vPt);
  2313.         vPt.vh[vhs] := fSize.vh[vhs] - gBreaksPenState.pnSize.vh[vhs];
  2314.         qdEndPt := ViewToQDPt(vPt);
  2315.  
  2316.         MoveTo(qdStartPt.h, qdStartPt.v);
  2317.         LineTo(qdEndPt.h, qdEndPt.v);
  2318.         END;
  2319.     END;
  2320. {$ENDC}
  2321.  
  2322. {--------------------------------------------------------------------------------------------------}
  2323. {$S ANonRes}
  2324.  
  2325. PROCEDURE TCellsView.GetPrintExtent(VAR printExtent: VRect); OVERRIDE;
  2326. { Overridden to provide for Print Selection command. }
  2327.  
  2328.     VAR
  2329.         aRect:                VRect;
  2330.         tlCell:             GridCell;
  2331.         brCell:             GridCell;
  2332.  
  2333.     BEGIN
  2334.     IF TCalcPrintHandler(fPrintHandler).fCmdNumber = cPrintSelection THEN
  2335.         BEGIN
  2336.         tlCell := fSelections^^.rgnBBox.topLeft;
  2337.         brCell := fSelections^^.rgnBBox.botRight;
  2338.         brCell.h := Min(brCell.h - 1, fCalcDocument.fInUseBounds.right);
  2339.         brCell.v := Min(brCell.v - 1, fCalcDocument.fInUseBounds.bottom);
  2340.         END
  2341.     ELSE
  2342.         BEGIN
  2343.         tlCell := fCalcDocument.fInUseBounds.topLeft;
  2344.         brCell := fCalcDocument.fInUseBounds.botRight;
  2345.         END;
  2346.  
  2347.     CellToVRect(tlCell, aRect);
  2348.     printExtent.topLeft := aRect.topLeft;
  2349.     CellToVRect(brCell, aRect);
  2350.     printExtent.botRight := aRect.botRight;
  2351.  
  2352.     {$IFC qDebug}
  2353.     IF gDebugPrinting THEN
  2354.         BEGIN
  2355.         WrLblVRect('printExtent ', printExtent);
  2356.         WRITELN;
  2357.         END;
  2358.     {$ENDC}
  2359.     END;
  2360.  
  2361. {***************************************************************************************************
  2362.     T R o w s V i e w
  2363. ***************************************************************************************************}
  2364. {$S AOpen}
  2365.  
  2366. PROCEDURE TRowsView.IRes(itsDocument: TDocument;
  2367.                          itsSuperView: TView;
  2368.                          VAR itsParams: Ptr); OVERRIDE;
  2369.  
  2370.     BEGIN
  2371.     fCalcDocument := TCalcDocument(itsDocument);
  2372.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2373.     END;
  2374.  
  2375. {--------------------------------------------------------------------------------------------------}
  2376. {$S ARes}
  2377.  
  2378. PROCEDURE TRowsView.AdornRow(aRow: INTEGER;
  2379.                              area: Rect); OVERRIDE;
  2380.  
  2381.     BEGIN
  2382.     PenSize(1, 1);
  2383.     PenPat(black);
  2384.  
  2385.     { right line }
  2386.     MoveTo(area.right - 1, area.top);
  2387.     LineTo(area.right - 1, area.bottom - 1);
  2388.  
  2389.     { bottom line }
  2390.     MoveTo(area.left, area.bottom - 1);
  2391.     LineTo(area.right - 1, area.bottom - 1);
  2392.     END;
  2393.  
  2394. {--------------------------------------------------------------------------------------------------}
  2395. {$S ASelCommand}
  2396.  
  2397. FUNCTION TRowsView.DoMouseCommand(VAR theMouse: Point;
  2398.                                   VAR info: EventInfo;
  2399.                                   VAR hysteresis: Point): TCommand; OVERRIDE;
  2400.  
  2401.     VAR
  2402.         aRowSelector:        TRowSelector;
  2403.  
  2404.     BEGIN
  2405.     NEW(aRowSelector);
  2406.     FailNIL(aRowSelector);
  2407.     aRowSelector.IRowSelector(fCalcDocument, SELF, info.theShiftKey, info.theCmdKey);
  2408.     DoMouseCommand := aRowSelector;
  2409.     WITH fCalcDocument DO
  2410.         BEGIN
  2411.         fSelectionType := RowSelection;
  2412.         fColumnsView.SetEmptySelection(kHighlight);
  2413.         fColumnIsSelected := FALSE;
  2414.         END;
  2415.     END;
  2416.  
  2417. {--------------------------------------------------------------------------------------------------}
  2418. {$S ARes}
  2419.  
  2420. FUNCTION TRowsView.DoSetCursor(localPoint: Point;
  2421.                                cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  2422.  
  2423.     BEGIN
  2424.     DoSetCursor := FALSE;
  2425.     END;
  2426.  
  2427. {--------------------------------------------------------------------------------------------------}
  2428. {$S ARes}
  2429.  
  2430. PROCEDURE TRowsView.DrawCell(aCell: GridCell;
  2431.                              aQDRect: Rect); OVERRIDE;
  2432.  
  2433.     VAR
  2434.         theString:            Str255;
  2435.  
  2436.     BEGIN
  2437.     NumToString(aCell.v, theString);
  2438.     WITH aQDRect DO                                        { aesthetic adjustment of the rect }
  2439.         top := top + 2;
  2440.     MADrawString(@theString, aQDRect, teJustCenter);
  2441.     END;
  2442.  
  2443. {--------------------------------------------------------------------------------------------------}
  2444. {$S AFields}
  2445.  
  2446. PROCEDURE TRowsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2447.                                                fieldAddr: Ptr;
  2448.                                                fieldType: INTEGER)); OVERRIDE;
  2449.  
  2450.     BEGIN
  2451.     DoToField('TRowsView', NIL, bClass);
  2452.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2453.     INHERITED Fields(DoToField);
  2454.     END;
  2455.  
  2456. {***************************************************************************************************
  2457.     T C o l u m n s V i e w
  2458. ***************************************************************************************************}
  2459. {$S AOpen}
  2460.  
  2461. PROCEDURE TColumnsView.IRes(itsDocument: TDocument;
  2462.                             itsSuperView: TView;
  2463.                             VAR itsParams: Ptr); OVERRIDE;
  2464.  
  2465.     BEGIN
  2466.     fCalcDocument := TCalcDocument(itsDocument);
  2467.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2468.     SetRowHeight(1, fNumOfRows, kCellHeight);
  2469.     fCalcDocument.fColumnIsSelected := FALSE;
  2470.     END;
  2471.  
  2472. {--------------------------------------------------------------------------------------------------}
  2473. {$S ARes}
  2474.  
  2475. PROCEDURE TColumnsView.AdornCol(aCol: INTEGER;
  2476.                                 area: Rect); OVERRIDE;
  2477.  
  2478.     BEGIN
  2479.     PenPat(black);
  2480.     PenSize(1, 1);
  2481.  
  2482.     { top line }
  2483.     MoveTo(area.left, area.top);
  2484.     LineTo(area.right - 1, area.top);
  2485.  
  2486.     { bottom line }
  2487.     MoveTo(area.left, area.bottom - 1);
  2488.     LineTo(area.right - 1, area.bottom - 1);
  2489.  
  2490.     { right line }
  2491.     MoveTo(area.right - 1, area.top);
  2492.     LineTo(area.right - 1, area.bottom - 1);
  2493.  
  2494.     END;
  2495.  
  2496. {--------------------------------------------------------------------------------------------------}
  2497. {$S ARes}
  2498.  
  2499. PROCEDURE TColumnsView.CoordToString(coord: INTEGER;
  2500.                                      VAR theString: Str255);
  2501.  
  2502.     BEGIN
  2503.     coord := coord - 1;
  2504.     IF coord < 26 THEN
  2505.         BEGIN
  2506.         theString := ' ';
  2507.         theString[1] := CHR(ORD('A') + coord);
  2508.         END
  2509.     ELSE
  2510.         BEGIN
  2511.         theString := '  ';
  2512.         theString[1] := CHR(ORD('A') + (coord DIV 26) - 1);
  2513.         theString[2] := CHR(ORD('A') + (coord MOD 26));
  2514.         END;
  2515.     END;
  2516.  
  2517. {--------------------------------------------------------------------------------------------------}
  2518. {$S ASelCommand}
  2519.  
  2520. FUNCTION TColumnsView.DoMouseCommand(VAR theMouse: Point;
  2521.                                      VAR info: EventInfo;
  2522.                                      VAR hysteresis: Point): TCommand; OVERRIDE;
  2523.  
  2524.     VAR
  2525.         aColumnSelector:    TColumnSelector;
  2526.         aColumnSizer:        TColumnSizer;
  2527.         aRow:                INTEGER;
  2528.         aCol:                INTEGER;
  2529.         whichPart:            GridViewPart;
  2530.         aCell:                GridCell;
  2531.  
  2532.     BEGIN
  2533.     DoMouseCommand := NIL;
  2534.     whichPart := IdentifyPoint(theMouse, aRow, aCol);
  2535.     aCell.h := aCol;
  2536.     aCell.v := aRow;
  2537.  
  2538.     CASE whichPart OF
  2539.         inCell:
  2540.             BEGIN
  2541.             fCalcDocument.fColumnIsSelected := TRUE;
  2542.             NEW(aColumnSelector);
  2543.             FailNIL(aColumnSelector);
  2544.             aColumnSelector.IColumnSelector(fCalcDocument, SELF, info.theShiftKey, info.theCmdKey);
  2545.             DoMouseCommand := aColumnSelector;
  2546.             fCalcDocument.fSelectionType := ColumnSelection;
  2547.             END;
  2548.  
  2549.         inColumn, inVertex:
  2550.             BEGIN
  2551.             IF aCol > 1 THEN
  2552.                 BEGIN
  2553.                 NEW(aColumnSizer);
  2554.                 FailNIL(aColumnSizer);
  2555.                 aColumnSizer.IColumnSizer(fCalcDocument, aCol - 1);
  2556.                 DoMouseCommand := aColumnSizer;
  2557.                 END;
  2558.             END;
  2559.  
  2560.         OTHERWISE;
  2561.     END;
  2562.     fCalcDocument.fRowsView.SetEmptySelection(kHighlight);
  2563.     END;
  2564.  
  2565. {--------------------------------------------------------------------------------------------------}
  2566. {$S ARes}
  2567.  
  2568. FUNCTION TColumnsView.DoSetCursor(localPoint: Point;
  2569.                                   cursorRgn: RgnHandle): BOOLEAN; OVERRIDE;
  2570.  
  2571.     VAR
  2572.         aRow:                INTEGER;
  2573.         aCol:                INTEGER;
  2574.         cellsExtent:        VRect;
  2575.         cellsQDExtent, columnQDExtent: Rect;
  2576.  
  2577.     BEGIN
  2578.     DoSetCursor := FALSE;
  2579.  
  2580.     CASE IdentifyPoint(localPoint, aRow, aCol) OF
  2581.         badChoice: ;
  2582.         inColumn, inVertex:
  2583.             IF aCol > 1 THEN
  2584.                 BEGIN
  2585.                 DoSetCursor := TRUE;
  2586.                 SetCursor(GetCursor(kColumnSizingCursor)^^);
  2587.                 ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  2588.                 ViewToQDRect(cellsExtent, cellsQDExtent);
  2589.                 columnQDExtent := cellsQDExtent;
  2590.  
  2591.                 { Which edge is the mouse closer to? }
  2592.                 IF abs(columnQDExtent.right - localPoint.h) < abs(columnQDExtent.left -
  2593.                                                                   localPoint.h) THEN
  2594.                     columnQDExtent.left := columnQDExtent.right;
  2595.  
  2596.                 columnQDExtent.left := columnQDExtent.left - fColInset DIV 2;
  2597.                 columnQDExtent.right := columnQDExtent.left + fColInset;
  2598.                 RectRgn(cursorRgn, columnQDExtent);
  2599.                 END;
  2600.         inRow, inCell:
  2601.             BEGIN
  2602.             DoSetCursor := TRUE;
  2603.             SetCursor(arrow);
  2604.             ColToVRect(Min(aCol, fNumOfCols), 1, cellsExtent);
  2605.             InsetVRect(cellsExtent, fColInset DIV 2, 0); { Account for the column resizer }
  2606.             ViewToQDRect(cellsExtent, cellsQDExtent);
  2607.             RectRgn(cursorRgn, cellsQDExtent);
  2608.             END;
  2609.     END;
  2610.     END;
  2611.  
  2612. {--------------------------------------------------------------------------------------------------}
  2613. {$S ARes}
  2614.  
  2615. PROCEDURE TColumnsView.DrawCell(aCell: GridCell;
  2616.                                 aQDRect: Rect); OVERRIDE;
  2617.  
  2618.     VAR
  2619.         theString:            Str255;
  2620.  
  2621.     BEGIN
  2622.     CoordToString(aCell.h, theString);
  2623.     WITH aQDRect DO                                        { aesthetic adjustment of the rect }
  2624.         top := top + 2;
  2625.     MADrawString(@theString, aQDRect, teJustCenter);
  2626.     END;
  2627.  
  2628. {--------------------------------------------------------------------------------------------------}
  2629. {$S ADoCommand}
  2630.  
  2631. PROCEDURE TColumnsView.ReSelect(cellRegion: RgnHandle);
  2632.  
  2633.     VAR
  2634.         aCell:                GridCell;
  2635.         cellsInColumn:        RgnHandle;
  2636.         cellsToSelect:        RgnHandle;
  2637.  
  2638. {--------------------------------------------------------------------------------------------------}
  2639.  
  2640.     PROCEDURE GetColumnCells(columnCell: GridCell);
  2641.  
  2642.         VAR
  2643.             aRect:                Rect;
  2644.  
  2645.         BEGIN
  2646.         SetRect(aRect, columnCell.h, 1, columnCell.h + 1, fCalcDocument.fCellsView.fNumOfRows + 1);
  2647.         RectRgn(cellsInColumn, aRect);
  2648.         UnionRgn(cellsInColumn, cellsToSelect, cellsToSelect);
  2649.         END;
  2650.  
  2651.     BEGIN
  2652.     aCell := cellRegion^^.rgnBBox.topLeft;
  2653.     IF NOT EqualRect(cellRegion^^.rgnBBox, fSelections^^.rgnBBox) THEN
  2654.         BEGIN                                            { selection has changed }
  2655.         WITH fCalcDocument DO
  2656.             BEGIN
  2657.             fCellsView.SetEmptySelection(kHighlight);
  2658.             fRowsView.SetEmptySelection(kHighlight);
  2659.             fColumnIsSelected := TRUE;
  2660.             END;
  2661.         SetSelection(cellRegion, kDontExtend, kHighlight, kSelect);
  2662.         cellsToSelect := MakeNewRgn;
  2663.         cellsInColumn := MakeNewRgn;
  2664.         EachSelectedCellDo(GetColumnCells);             { add cells in the column to cellsToSelect }
  2665.         fCalcDocument.fCellsView.SetSelection(cellsToSelect, kDontExtend, kHighlight, kSelect);
  2666.         DisposeRgn(cellsToSelect);
  2667.         DisposeRgn(cellsInColumn);
  2668.         END;
  2669.     END;
  2670.  
  2671. {--------------------------------------------------------------------------------------------------}
  2672. {$S AFields}
  2673.  
  2674. PROCEDURE TColumnsView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2675.                                                   fieldAddr: Ptr;
  2676.                                                   fieldType: INTEGER)); OVERRIDE;
  2677.  
  2678.     BEGIN
  2679.     DoToField('TColumnsView', NIL, bClass);
  2680.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2681.     INHERITED Fields(DoToField);
  2682.     END;
  2683.  
  2684. {***************************************************************************************************
  2685.     T C a l c P r i n t H a n d l e r
  2686. ***************************************************************************************************}
  2687. {$S ANonRes}
  2688.  
  2689. PROCEDURE TCalcPrintHandler.CalcViewPerPage(VAR amtPerPage: VPoint); OVERRIDE;
  2690.  
  2691.     VAR
  2692.         noOfRows:            INTEGER;
  2693.  
  2694.     BEGIN
  2695.     INHERITED CalcViewPerPage(amtPerPage);
  2696.     noOfRows := amtPerPage.v DIV kCellHeight;
  2697.     amtPerPage.v := noOfRows * kCellHeight;
  2698.     END;
  2699.  
  2700. {--------------------------------------------------------------------------------------------------}
  2701. {$S ANonRes}
  2702.  
  2703. FUNCTION TCalcPrintHandler.DoMenuCommand(aCmdNumber: cmdNumber): TCommand; OVERRIDE;
  2704. { Overridden to handle Print Selection. }
  2705.  
  2706.     BEGIN
  2707.     DoMenuCommand := NIL;
  2708.     fCmdNumber := aCmdNumber;                            { Save cmd number for GetPrintExtent }
  2709.     IF aCmdNumber = cPrintSelection THEN
  2710.         aCmdNumber := cPrint;                            { proceed like regular Print }
  2711.     DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  2712.     END;
  2713.  
  2714. {--------------------------------------------------------------------------------------------------}
  2715. {$S ANonRes}
  2716.  
  2717. PROCEDURE TCalcPrintHandler.DoSetupMenus; OVERRIDE;
  2718. { Overridden to handle Print Selection. }
  2719.  
  2720.     BEGIN
  2721.     INHERITED DoSetupMenus;
  2722.     Enable(cPrintSelection, gCouldPrint & (fView <> NIL));
  2723.     END;
  2724.  
  2725. {***************************************************************************************************
  2726.     T E n t r y V i e w
  2727. ***************************************************************************************************}
  2728. {$S AOpen}
  2729.  
  2730. PROCEDURE TEntryView.IRes(itsDocument: TDocument;
  2731.                           itsSuperView: TView;
  2732.                           VAR itsParams: Ptr); OVERRIDE;
  2733.  
  2734.     VAR
  2735.         minSize:            Point;
  2736.  
  2737.     BEGIN
  2738.     INHERITED IRes(NIL, itsSuperView, itsParams);        { set itsDocument to NIL since this guy
  2739.                                                          doesn't affect the document }
  2740.     fCalcDocument := TCalcDocument(itsDocument);
  2741.     fTouched := FALSE;
  2742.     fTEditing := FALSE;
  2743.     fFirstEdit := FALSE;
  2744.     fOldString := '';
  2745.     END;
  2746.  
  2747. {--------------------------------------------------------------------------------------------------}
  2748. {$S ARes}
  2749.  
  2750. FUNCTION TEntryView.DoKeyCommand(Ch: CHAR;
  2751.                                  aKeyCode: INTEGER;
  2752.                                  VAR info: EventInfo): TCommand; OVERRIDE;
  2753.  
  2754.     BEGIN
  2755.     { If this is the first character, wipe out old value and activate caret. }
  2756.     IF (NOT fTEditing) & ((Ch >= ' ') | (Ch = chBackspace)) THEN
  2757.         SetEditMode;
  2758.     DoKeyCommand := INHERITED DoKeyCommand(Ch, aKeyCode, info);
  2759.     END;
  2760.  
  2761. {--------------------------------------------------------------------------------------------------}
  2762. {$S ASelCommand}
  2763.  
  2764. FUNCTION TEntryView.DoMakeTypingCommand(Ch: CHAR): TTETypingCommand; OVERRIDE;
  2765.  
  2766.     VAR
  2767.         aTypingCommand:     TCalcTypingCommand;
  2768.  
  2769.     BEGIN
  2770.     NEW(aTypingCommand);
  2771.     FailNIL(aTypingCommand);
  2772.     aTypingCommand.ITETypingCommand(SELF, Ch);
  2773.     DoMakeTypingCommand := aTypingCommand;
  2774.     END;
  2775.  
  2776. {--------------------------------------------------------------------------------------------------}
  2777. {$S ASelCommand}
  2778.  
  2779. FUNCTION TEntryView.DoMouseCommand(VAR theMouse: Point;
  2780.                                    VAR info: EventInfo;
  2781.                                    VAR hysteresis: Point): TCommand; OVERRIDE;
  2782.  
  2783.     BEGIN
  2784.     { If no characters typed, active caret, then handle mouse down. }
  2785.     IF NOT fTouched THEN
  2786.         InstallSelection(FALSE, TRUE);
  2787.     EditMode(TRUE);
  2788.     DoMouseCommand := INHERITED DoMouseCommand(theMouse, info, hysteresis);
  2789.     END;
  2790.  
  2791. {--------------------------------------------------------------------------------------------------}
  2792. {$S ARes}
  2793.  
  2794. PROCEDURE TEntryView.DoSetupMenus; OVERRIDE;
  2795.  
  2796.     BEGIN
  2797.     { TTEView.DoSetupMenus will setup the Edit menu commands for us. }
  2798.     INHERITED DoSetupMenus;
  2799.  
  2800.     IF fTEditing THEN
  2801.         BEGIN
  2802.         SetEditCmdName(cCut, cCutText);
  2803.         SetEditCmdName(cCopy, cCopyText);
  2804.         SetEditCmdName(cClear, cClearText);
  2805.         END;
  2806.     END;
  2807.  
  2808. {--------------------------------------------------------------------------------------------------}
  2809. {$S ARes}
  2810.  
  2811. PROCEDURE TEntryView.Draw(area: Rect); OVERRIDE;
  2812.  
  2813.     VAR
  2814.         r:                    Rect;
  2815.  
  2816.     BEGIN
  2817.     INHERITED Draw(area);
  2818.  
  2819.     { We want a rectangle around the whole view }
  2820.     PenSize(1, 1);
  2821.     PenPat(black);
  2822.     GetQDExtent(r);
  2823.     FrameRect(r);
  2824.  
  2825.     INHERITED Draw(area);
  2826.     END;
  2827.  
  2828. {--------------------------------------------------------------------------------------------------}
  2829. {$S ASelCommand}
  2830.  
  2831. PROCEDURE TEntryView.EditMode(editing: BOOLEAN);
  2832.  
  2833.     VAR
  2834.         lastCommand:        TCommand;
  2835.  
  2836.     BEGIN
  2837.     fTEditing := editing;
  2838.     fFirstEdit := FALSE;                                { set to TRUE only by DoKeyCommand }
  2839.  
  2840.     IF editing THEN
  2841.         BEGIN
  2842.         {$Push} {$H-}
  2843.         GetAsString(fOldString);                        { save previous string for Undo/Redo }
  2844.         {$Pop}
  2845.         END
  2846.     ELSE
  2847.         BEGIN                                            { disable undo/redo for TTECommands. ???
  2848.                                                          There must be a better way! this is
  2849.                                                          disgusting! }
  2850.         lastCommand := GetLastCommand;
  2851.         IF lastCommand <> NIL THEN
  2852.             IF GetSuperClassID(GetClassID(lastCommand)) = GetClassIDFromName('TTECommand') THEN
  2853.                 lastCommand.fCanUndo := FALSE;
  2854.         END;
  2855.     END;
  2856.  
  2857. {--------------------------------------------------------------------------------------------------}
  2858. {$S ARes}
  2859.  
  2860. PROCEDURE TEntryView.GetAsString(VAR theString: Str255);
  2861.  
  2862.     VAR
  2863.         theText:            CharsHandle;
  2864.         numberOfChars:        INTEGER;
  2865.         i:                    INTEGER;
  2866.  
  2867.     BEGIN
  2868.     theText := TEGetText(fHTE);
  2869.     numberOfChars := Min(255, GetHandleSize(Handle(theText)));
  2870.     theString[0] := CHR(numberOfChars);
  2871.     FOR i := 1 TO numberOfChars DO
  2872.         theString[i] := theText^^[i - 1];
  2873.     END;
  2874.  
  2875. {--------------------------------------------------------------------------------------------------}
  2876. {$S ARes}
  2877.  
  2878. PROCEDURE TEntryView.InstallSelection(wasActive, beActive: BOOLEAN); OVERRIDE;
  2879.  
  2880.     VAR
  2881.         r:                    Rect;
  2882.  
  2883.     BEGIN
  2884.     INHERITED InstallSelection(wasActive, beActive);
  2885.  
  2886.     TESetSelect(0, 0, fHTE);
  2887.     fTouched := beActive;
  2888.     IF Focus THEN
  2889.         BEGIN
  2890.         GetQDExtent(r);
  2891.         InsetRect(r, 2, 2);
  2892.         InvalidRect(r);
  2893.         END;
  2894.     END;
  2895.  
  2896. {--------------------------------------------------------------------------------------------------}
  2897. {$S ASelCommand}
  2898.  
  2899. PROCEDURE TEntryView.SetEditMode;
  2900.  
  2901.     BEGIN
  2902.     EditMode(TRUE);                                     { sets fFirstEdit to FALSE }
  2903.     fFirstEdit := TRUE;                                 { the only place it is set to TRUE }
  2904.     SetToString('');
  2905.     InstallSelection(FALSE, TRUE);
  2906.     END;
  2907.  
  2908. {--------------------------------------------------------------------------------------------------}
  2909. {$S ARes}
  2910.  
  2911. PROCEDURE TEntryView.SetToString(theString: Str255);
  2912.  
  2913.     BEGIN
  2914.     IF Focus THEN;
  2915.     SetJustification(teJustSystem, kDontRedraw);        { initialize text to system-justified }
  2916.     InstallSelection(TRUE, FALSE);
  2917.     TESetText(Ptr(ORD4(@theString) + 1), LENGTH(theString), fHTE);
  2918.     END;
  2919.  
  2920. {--------------------------------------------------------------------------------------------------}
  2921. {$S ADoCommand}
  2922.  
  2923. PROCEDURE TEntryView.SwapStrings;
  2924.  
  2925.     VAR
  2926.         newString:            Str255;
  2927.  
  2928.     BEGIN
  2929.     newString := fOldString;
  2930.     {$Push} {$H-}
  2931.     GetAsString(fOldString);
  2932.     {$Pop}
  2933.     SetToString(newString);
  2934.     fTouched := TRUE;
  2935.     END;
  2936.  
  2937. {--------------------------------------------------------------------------------------------------}
  2938. {$S AFields}
  2939.  
  2940. PROCEDURE TEntryView.Fields(PROCEDURE DoToField(fieldName: Str255;
  2941.                                                 fieldAddr: Ptr;
  2942.                                                 fieldType: INTEGER)); OVERRIDE;
  2943.  
  2944.     BEGIN
  2945.     DoToField('TEntryView', NIL, bClass);
  2946.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  2947.     DoToField('fTouched', @fTouched, bBoolean);
  2948.     DoToField('fTEditing', @fTEditing, bBoolean);
  2949.     DoToField('fFirstEdit', @fFirstEdit, bBoolean);
  2950.     DoToField('fOldString', @fOldString, bString);
  2951.     INHERITED Fields(DoToField);
  2952.     END;
  2953.  
  2954. {***************************************************************************************************
  2955.     T C o o r d V i e w
  2956. ***************************************************************************************************}
  2957. {$S AOpen}
  2958.  
  2959. PROCEDURE TCoordView.IRes(itsDocument: TDocument;
  2960.                           itsSuperView: TView;
  2961.                           VAR itsParams: Ptr); OVERRIDE;
  2962.  
  2963.     VAR
  2964.         minSize:            Point;
  2965.  
  2966.     BEGIN
  2967.     fCalcDocument := TCalcDocument(itsDocument);
  2968.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  2969.     END;
  2970.  
  2971. {--------------------------------------------------------------------------------------------------}
  2972. {$S ARes}
  2973.  
  2974. PROCEDURE TCoordView.Draw(area: Rect);
  2975.  
  2976.     VAR
  2977.         aString, anotherString: Str255;
  2978.         aRect:Rect;
  2979.  
  2980.     BEGIN
  2981.     WITH fCalcDocument DO
  2982.         BEGIN
  2983.         IF fEditColumn > 0 THEN
  2984.             fColumnsView.CoordToString(fEditColumn, aString)
  2985.         ELSE
  2986.             aString := ' ';
  2987.  
  2988.         IF fEditRow > 0 THEN
  2989.             NumToString(fEditRow, anotherString)
  2990.         ELSE
  2991.             anotherString := ' ';
  2992.         END;
  2993.     aString := CONCAT(aString, anotherString);
  2994.     SetTheFont(kEntryFont, kEntryFontSize, [bold]);
  2995.     SetRect(aRect, 2, 0, 46, kEntryHeight);
  2996.     SmartDrawString(aString, aRect, teJustSystem);
  2997.  
  2998.     INHERITED Draw(area);
  2999.     END;
  3000.  
  3001. {--------------------------------------------------------------------------------------------------}
  3002. {$S AFields}
  3003.  
  3004. PROCEDURE TCoordView.Fields(PROCEDURE DoToField(fieldName: Str255;
  3005.                                                 fieldAddr: Ptr;
  3006.                                                 fieldType: INTEGER)); OVERRIDE;
  3007.  
  3008.     BEGIN
  3009.     DoToField('TCoordView', NIL, bClass);
  3010.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  3011.     INHERITED Fields(DoToField);
  3012.     END;
  3013.  
  3014. {***************************************************************************************************
  3015.     T C o l u m n
  3016. ***************************************************************************************************}
  3017. {$S ARes}
  3018.  
  3019. PROCEDURE TColumn.Initialize; OVERRIDE;
  3020. { Put the object into a known state from which it may be safely FREEd.
  3021.  (and hopefully a usable state) }
  3022.  
  3023.     BEGIN
  3024.     INHERITED Initialize;
  3025.  
  3026.     fNumber := 0;
  3027.     fFormat := gDefaultFormat;
  3028.     fWidth := kCellWidth;
  3029.     END;
  3030.  
  3031. {--------------------------------------------------------------------------------------------------}
  3032. {$S ARes}
  3033.  
  3034. PROCEDURE TColumn.IColumn(number: INTEGER);
  3035.  
  3036.     BEGIN
  3037.     IObject;
  3038.  
  3039.     fNumber := number;
  3040.     END;
  3041.  
  3042. {--------------------------------------------------------------------------------------------------}
  3043. {$S AFields}
  3044.  
  3045. PROCEDURE TColumn.Fields(PROCEDURE DoToField(fieldName: Str255;
  3046.                                              fieldAddr: Ptr;
  3047.                                              fieldType: INTEGER)); OVERRIDE;
  3048.  
  3049.     BEGIN
  3050.     DoToField('TColumn', NIL, bClass);
  3051.     DoToField('fNumber', @fNumber, bInteger);
  3052.     {$Push} {$H-}                                        { Because FormatFields is in a debugging
  3053.                                                          (i.e. resident) segment) }
  3054.     FormatFields('fFormat', fFormat, DoToField);
  3055.     {$Pop}
  3056.     DoToField('fWidth', @fWidth, bInteger);
  3057.  
  3058.     INHERITED Fields(DoToField);
  3059.     END;
  3060.  
  3061. {--------------------------------------------------------------------------------------------------}
  3062. {$S AReadFile}
  3063.  
  3064. PROCEDURE TColumn.ReadFromDisk(theRefNum: INTEGER);
  3065.  
  3066.     VAR
  3067.         columnInfo:         ColumnDiskInfo;
  3068.  
  3069.     BEGIN
  3070.     ReadBytes(theRefNum, SIZEOF(columnInfo), @columnInfo);
  3071.     WITH columnInfo DO
  3072.         BEGIN
  3073.         fNumber := number;
  3074.         fFormat := format;
  3075.         fWidth := width;
  3076.         END;
  3077.     END;
  3078.  
  3079. {--------------------------------------------------------------------------------------------------}
  3080. {$S AClipBoard}
  3081.  
  3082. PROCEDURE TColumn.ReadFromScrap(theScrap: Handle;
  3083.                                 VAR scrapOffset: LONGINT);
  3084.  
  3085.     VAR
  3086.         columnInfo:         ColumnDiskInfo;
  3087.  
  3088.     BEGIN
  3089.     ReadScrap(theScrap, scrapOffset, @columnInfo, SIZEOF(columnInfo));
  3090.     WITH columnInfo DO
  3091.         BEGIN
  3092.         fNumber := number;
  3093.         fFormat := format;
  3094.         fWidth := width;
  3095.         END;
  3096.     END;
  3097.  
  3098. {--------------------------------------------------------------------------------------------------}
  3099. {$S AWriteFile}
  3100.  
  3101. PROCEDURE TColumn.WriteToDisk(theRefNum: INTEGER);
  3102.  
  3103.     VAR
  3104.         columnInfo:         ColumnDiskInfo;
  3105.         theColumn:            ColumnNumber;
  3106.  
  3107.     BEGIN
  3108.     theColumn := fNumber;
  3109.     WriteBytes(theRefNum, SIZEOF(ColumnNumber), @theColumn);
  3110.  
  3111.     WITH columnInfo DO
  3112.         BEGIN
  3113.         number := fNumber;
  3114.         format := fFormat;
  3115.         width := fWidth;
  3116.         END;
  3117.     WriteBytes(theRefNum, SIZEOF(columnInfo), @columnInfo);
  3118.     END;
  3119.  
  3120. {--------------------------------------------------------------------------------------------------}
  3121. {$S AClipBoard}
  3122.  
  3123. PROCEDURE TColumn.WriteToScrap(theScrap: Handle;
  3124.                                VAR scrapOffset: LONGINT);
  3125.  
  3126.     VAR
  3127.         columnInfo:         ColumnDiskInfo;
  3128.  
  3129.     BEGIN
  3130.     WITH columnInfo DO
  3131.         BEGIN
  3132.         number := fNumber;
  3133.         format := fFormat;
  3134.         width := fWidth;
  3135.         END;
  3136.     WriteScrap(theScrap, scrapOffset, @columnInfo, SIZEOF(columnInfo));
  3137.     END;
  3138.  
  3139. {***************************************************************************************************
  3140.     T R o w
  3141. ***************************************************************************************************}
  3142. {$S ARes}
  3143.  
  3144. PROCEDURE TRow.Initialize; OVERRIDE;
  3145. { Put the object into a known state from which it may be safely FREEd.
  3146.  (and hopefully a usable state) }
  3147.  
  3148.     BEGIN
  3149.     INHERITED Initialize;
  3150.  
  3151.     fNumber := 0;
  3152.     END;
  3153.  
  3154. {--------------------------------------------------------------------------------------------------}
  3155. {$S ARes}
  3156.  
  3157. PROCEDURE TRow.IRow(number: INTEGER);
  3158.  
  3159.     BEGIN
  3160.     IObject;
  3161.  
  3162.     fNumber := number;
  3163.     END;
  3164.  
  3165. {--------------------------------------------------------------------------------------------------}
  3166. {$S AFields}
  3167.  
  3168. PROCEDURE TRow.Fields(PROCEDURE DoToField(fieldName: Str255;
  3169.                                           fieldAddr: Ptr;
  3170.                                           fieldType: INTEGER)); OVERRIDE;
  3171.  
  3172.     BEGIN
  3173.     DoToField('TRow', NIL, bClass);
  3174.     DoToField('fNumber', @fNumber, bInteger);
  3175.     INHERITED Fields(DoToField)
  3176.     END;
  3177.  
  3178. {--------------------------------------------------------------------------------------------------}
  3179. {$S AReadFile}
  3180.  
  3181. PROCEDURE TRow.ReadFromDisk(theRefNum: INTEGER);
  3182.  
  3183.     VAR
  3184.         RowInfo:            RowDiskInfo;
  3185.  
  3186.     BEGIN
  3187.     ReadBytes(theRefNum, SIZEOF(RowInfo), @RowInfo);
  3188.     WITH RowInfo DO
  3189.         fNumber := number;
  3190.     END;
  3191.  
  3192. {--------------------------------------------------------------------------------------------------}
  3193. {$S AClipBoard}
  3194.  
  3195. PROCEDURE TRow.ReadFromScrap(theScrap: Handle;
  3196.                              VAR scrapOffset: LONGINT);
  3197.  
  3198.     VAR
  3199.         RowInfo:            RowDiskInfo;
  3200.  
  3201.     BEGIN
  3202.     ReadScrap(theScrap, scrapOffset, @RowInfo, SIZEOF(RowInfo));
  3203.     WITH RowInfo DO
  3204.         fNumber := number;
  3205.     END;
  3206.  
  3207. {--------------------------------------------------------------------------------------------------}
  3208. {$S AWriteFile}
  3209.  
  3210. PROCEDURE TRow.WriteToDisk(theRefNum: INTEGER);
  3211.  
  3212.     VAR
  3213.         RowInfo:            RowDiskInfo;
  3214.         theRow:             RowNumber;
  3215.  
  3216.     BEGIN
  3217.     theRow := fNumber;
  3218.     WriteBytes(theRefNum, SIZEOF(RowNumber), @theRow);
  3219.  
  3220.     WITH RowInfo DO
  3221.         number := fNumber;
  3222.     WriteBytes(theRefNum, SIZEOF(RowInfo), @RowInfo);
  3223.     END;
  3224.  
  3225. {--------------------------------------------------------------------------------------------------}
  3226. {$S AClipBoard}
  3227.  
  3228. PROCEDURE TRow.WriteToScrap(theScrap: Handle;
  3229.                             VAR scrapOffset: LONGINT);
  3230.  
  3231.     VAR
  3232.         RowInfo:            RowDiskInfo;
  3233.  
  3234.     BEGIN
  3235.     WITH RowInfo DO
  3236.         number := fNumber;
  3237.     WriteScrap(theScrap, scrapOffset, @RowInfo, SIZEOF(RowInfo));
  3238.     END;
  3239.  
  3240. {***************************************************************************************************
  3241.     T C e l l
  3242. ***************************************************************************************************}
  3243. {$S ARes}
  3244.  
  3245. PROCEDURE TCell.Initialize; OVERRIDE;
  3246.  
  3247.     BEGIN
  3248.     INHERITED Initialize;
  3249.  
  3250.     fCalcDocument := NIL;
  3251.     fDeleted := FALSE;
  3252.     fDependents := NIL;
  3253.     fReferences := NIL;
  3254.  
  3255.     fKind := EmptyCell;
  3256.     fError := NoError;
  3257.     fValue := 0.0;
  3258.     fValueString := '';
  3259.     fFormula := '';
  3260.     FailMemError;
  3261.  
  3262.     fRow := 0;
  3263.     fColumn := 0;
  3264.     fEvaluating := FALSE;
  3265.     fCalculating := FALSE;
  3266.     END;
  3267.  
  3268. {--------------------------------------------------------------------------------------------------}
  3269. {$S ARes}
  3270.  
  3271. PROCEDURE TCell.ICell(owningDocument: TCalcDocument;
  3272.                       r: RowNumber;
  3273.                       c: ColumnNumber);
  3274.  
  3275.     BEGIN
  3276.     IObject;
  3277.  
  3278.     fCalcDocument := owningDocument;
  3279.  
  3280.     fDependents := NewList;
  3281.     FailNIL(fDependents);
  3282.  
  3283.     fReferences := NewList;
  3284.     FailNIL(fReferences);
  3285.  
  3286.     {$IFC qDebug}
  3287.     fDependents.SetEltType('TCell');
  3288.     fReferences.SetEltType('TCell');
  3289.     {$ENDC}
  3290.  
  3291.     fRow := r;
  3292.     fColumn := c;
  3293.     END;
  3294.  
  3295. {--------------------------------------------------------------------------------------------------}
  3296. {$S ARes}
  3297.  
  3298. PROCEDURE TCell.Free;
  3299.  
  3300.     BEGIN
  3301.     FreeIfObject(fDependents);
  3302.     fDependents := NIL;
  3303.  
  3304.     FreeIfObject(fReferences);
  3305.     fReferences := NIL;
  3306.  
  3307.     INHERITED Free;
  3308.     END;
  3309.  
  3310. {--------------------------------------------------------------------------------------------------}
  3311. {$S ARes}
  3312.  
  3313. FUNCTION TCell.Clone: TObject; OVERRIDE;
  3314.  
  3315.     VAR
  3316.         clonedCell:         TCell;
  3317.  
  3318.     BEGIN
  3319.     clonedCell := TCell(INHERITED Clone);
  3320.     FailNIL(clonedCell);
  3321.  
  3322.     clonedCell.fDependents := NewList;
  3323.     FailNIL(clonedCell.fDependents);
  3324.  
  3325.     clonedCell.fReferences := NewList;
  3326.     FailNIL(clonedCell.fReferences);
  3327.  
  3328.     {$IFC qDebug}
  3329.     clonedCell.fDependents.SetEltType('TCell');
  3330.     clonedCell.fReferences.SetEltType('TCell');
  3331.     {$ENDC}
  3332.  
  3333.     Clone := TObject(clonedCell);
  3334.     END;
  3335.  
  3336. {--------------------------------------------------------------------------------------------------}
  3337. {$S ARes}
  3338.  
  3339. PROCEDURE TCell.CopyContents(sourceCell: TCell);
  3340.  
  3341.     BEGIN
  3342.     fKind := sourceCell.fKind;
  3343.     fFormula := sourceCell.fFormula;
  3344.     END;
  3345.  
  3346. {--------------------------------------------------------------------------------------------------}
  3347. {$S ARes}
  3348.  
  3349. PROCEDURE TCell.EvaluateFormula(DoReferences: BOOLEAN);
  3350.  
  3351.     VAR
  3352.         formulaLength:        INTEGER;
  3353.         formulaIndex:        INTEGER;
  3354.         theChar:            CHAR;
  3355.         theValue:            ValueType;
  3356.  
  3357. {--------------------------------------------------------------------------------------------------}
  3358.  
  3359.     FUNCTION Factor(VAR theValue: ValueType): EvalResult;
  3360.         FORWARD;
  3361.  
  3362. {--------------------------------------------------------------------------------------------------}
  3363.  
  3364.     FUNCTION Expression(VAR theValue: ValueType): EvalResult;
  3365.         FORWARD;
  3366.  
  3367. {--------------------------------------------------------------------------------------------------}
  3368.  
  3369.     PROCEDURE GetNextChar;
  3370.  
  3371.         BEGIN
  3372.         REPEAT
  3373.             IF formulaIndex < formulaLength THEN
  3374.                 BEGIN
  3375.                 formulaIndex := formulaIndex + 1;
  3376.                 theChar := fFormula[formulaIndex];
  3377.                 END
  3378.             ELSE
  3379.                 theChar := CHR(0);
  3380.         UNTIL theChar <> ' ';
  3381.         IF (theChar >= 'a') & (theChar <= 'z') THEN
  3382.             theChar := CHR(ORD(theChar) - 32);
  3383.         END;
  3384.  
  3385. {--------------------------------------------------------------------------------------------------}
  3386.  
  3387.     FUNCTION DoInteger(VAR theInteger: INTEGER): EvalResult;
  3388.  
  3389.         BEGIN
  3390.         theInteger := 0;
  3391.         WHILE IsDigit(theChar) DO
  3392.             BEGIN
  3393.             theInteger := theInteger * 10 + ORD(theChar) - ORD('0');
  3394.             GetNextChar;
  3395.             END;
  3396.         DoInteger := NoError;
  3397.         END;
  3398.  
  3399. {--------------------------------------------------------------------------------------------------}
  3400.  
  3401.     FUNCTION DoNumber(VAR theValue: ValueType): EvalResult;
  3402.     { DoNumber is called only when theChar is a numeric digit or a decimal point }
  3403.  
  3404.         VAR
  3405.             newIndex:            INTEGER;
  3406.             decimalNumber:        Decimal;
  3407.             IsValidNumber:        BOOLEAN;
  3408.             startsWithDecPt:    BOOLEAN;
  3409.             theFormula:         Str255;
  3410.  
  3411.         BEGIN
  3412.         startsWithDecPt := (theChar = '.');
  3413.         newIndex := formulaIndex;
  3414.         theFormula := fFormula;
  3415.         Str2Dec(theFormula, newIndex, decimalNumber, IsValidNumber);
  3416.         { Str2Dec returns IsValidNumber = FALSE if the digits are followed by non-numerics like * }
  3417.         IF startsWithDecPt & (NOT IsValidNumber) THEN
  3418.             BEGIN
  3419.             GetNextChar;
  3420.             IF NOT IsDigit(theChar) THEN
  3421.                 BEGIN
  3422.                 DoNumber := BadNumber;
  3423.                 EXIT(DoNumber);
  3424.                 END;
  3425.             END;
  3426.         formulaIndex := newIndex - 1;
  3427.         GetNextChar;
  3428.         theValue := Dec2Num(decimalNumber);
  3429.         DoNumber := NoError;
  3430.         END;
  3431.  
  3432. {--------------------------------------------------------------------------------------------------}
  3433.  
  3434.     FUNCTION DoCellReference(VAR theValue: ValueType): EvalResult;
  3435.  
  3436.         VAR
  3437.             theResult:            EvalResult;
  3438.             r:                    INTEGER;                { Can't use RowNumber because it may be }
  3439.             c:                    INTEGER;                { …out of range }
  3440.             referencedCell:     TCell;
  3441.             aRect:                Rect;
  3442.  
  3443.         BEGIN
  3444.         theResult := NoError;
  3445.         aRect := fCalcDocument.fDimensions;             { valid coordinates }
  3446.         c := 0;
  3447.         WHILE (theChar >= 'A') & (theChar <= 'Z') & (c <= aRect.right) DO
  3448.             BEGIN
  3449.             c := c * 26 + ORD(theChar) - ORD('A') + 1;
  3450.             GetNextChar;
  3451.             END;
  3452.         IF c > aRect.right THEN                         { column is out of range, so }
  3453.             r := 0                                        { …don't bother looking for row number }
  3454.         ELSE
  3455.             theResult := DoInteger(r);
  3456.         IF fCalcDocument.CellInRange(r, c, aRect) THEN
  3457.             BEGIN
  3458.             referencedCell := fCalcDocument.GetExistingCell(r - fCalcDocument.fRowOffset, c -
  3459.                                                             fCalcDocument.fColumnOffset);
  3460.             IF referencedCell = NIL THEN                { cell doesn't exist }
  3461.                 theValue := 0
  3462.             ELSE
  3463.                 BEGIN
  3464.                 IF referencedCell.fEvaluating THEN
  3465.                     theResult := SelfReference
  3466.                 ELSE IF (referencedCell.fKind = ErrorCell) THEN
  3467.                     theResult := ErrorCellReference
  3468.                 ELSE IF (referencedCell.fKind = TextCell) THEN
  3469.                     theValue := 0
  3470.                 ELSE
  3471.                     theValue := referencedCell.fValue;
  3472.  
  3473.                 IF DoReferences THEN
  3474.                     BEGIN
  3475.                     fReferences.InsertLast(referencedCell);
  3476.                     referencedCell.fDependents.InsertLast(SELF);
  3477.                     END;
  3478.                 END;
  3479.             END
  3480.         ELSE
  3481.             theResult := BadCellReference;
  3482.         DoCellReference := theResult;
  3483.         END;
  3484.  
  3485. {--------------------------------------------------------------------------------------------------}
  3486.  
  3487.     FUNCTION Term(VAR theValue: ValueType): EvalResult;
  3488.  
  3489.         BEGIN
  3490.         IF theChar = '(' THEN
  3491.             BEGIN
  3492.             GetNextChar;
  3493.             Term := Expression(theValue);
  3494.             IF theChar = ')' THEN
  3495.                 GetNextChar
  3496.             ELSE
  3497.                 Term := MissingRightParen;
  3498.             END
  3499.         ELSE IF IsDigit(theChar) | (theChar = '.') THEN
  3500.             Term := DoNumber(theValue)
  3501.         ELSE IF (theChar >= 'A') & (theChar <= 'Z') THEN
  3502.             Term := DoCellReference(theValue)
  3503.         ELSE IF theChar = '+' THEN
  3504.             BEGIN
  3505.             GetNextChar;
  3506.             Term := Term(theValue);
  3507.             END
  3508.         ELSE IF theChar = '-' THEN
  3509.             BEGIN
  3510.             GetNextChar;
  3511.             Term := Term(theValue);
  3512.             theValue := - theValue;
  3513.             END
  3514.         ELSE
  3515.             Term := IllegalCharacter;
  3516.         END;
  3517.  
  3518. {--------------------------------------------------------------------------------------------------}
  3519.  
  3520.     FUNCTION Factor(VAR theValue: ValueType): EvalResult;
  3521.  
  3522.         VAR
  3523.             theResult:            EvalResult;
  3524.             factorValue:        ValueType;
  3525.  
  3526.         BEGIN
  3527.         theResult := Term(theValue);
  3528.         IF theResult = NoError THEN
  3529.             IF theChar = '*' THEN
  3530.                 BEGIN
  3531.                 GetNextChar;
  3532.                 theResult := Factor(factorValue);
  3533.                 theValue := theValue * factorValue;
  3534.                 END
  3535.             ELSE IF theChar = '/' THEN
  3536.                 BEGIN
  3537.                 GetNextChar;
  3538.                 theResult := Factor(factorValue);
  3539.                 theValue := theValue / factorValue;
  3540.                 END;
  3541.         Factor := theResult;
  3542.         END;
  3543.  
  3544. {--------------------------------------------------------------------------------------------------}
  3545.  
  3546.     FUNCTION Expression(VAR theValue: ValueType): EvalResult;
  3547.  
  3548.         VAR
  3549.             factorResult:        EvalResult;
  3550.             factorValue:        ValueType;
  3551.  
  3552.         BEGIN
  3553.         factorResult := Factor(theValue);
  3554.         IF factorResult = NoError THEN
  3555.             REPEAT
  3556.                 IF theChar = '+' THEN
  3557.                     BEGIN
  3558.                     GetNextChar;
  3559.                     factorResult := Factor(factorValue);
  3560.                     theValue := theValue + factorValue;
  3561.                     END
  3562.                 ELSE IF theChar = '-' THEN
  3563.                     BEGIN
  3564.                     GetNextChar;
  3565.                     factorResult := Factor(factorValue);
  3566.                     theValue := theValue - factorValue;
  3567.                     END;
  3568.             UNTIL (theChar <> '+') & (theChar <> '-');
  3569.         Expression := factorResult;
  3570.         END;
  3571.  
  3572.     BEGIN                                                { EvaluateFormula }
  3573.     formulaLength := LENGTH(fFormula);
  3574.     formulaIndex := 0;
  3575.     GetNextChar;
  3576.     IF theChar IN ['=', '-', '+', '.', '0'..'9'] THEN
  3577.         BEGIN
  3578.         IF theChar = '=' THEN
  3579.             GetNextChar;
  3580.  
  3581.         fEvaluating := TRUE;                            { prevent self reference loop }
  3582.         fError := Expression(theValue);
  3583.         fEvaluating := FALSE;
  3584.  
  3585.         IF fError = NoError THEN
  3586.             BEGIN
  3587.             fValue := theValue;
  3588.             IF (formulaIndex <= formulaLength) & (theChar <> CHR(0)) THEN
  3589.                 fError := GarbageAtEnd;
  3590.             END;
  3591.         IF fError = NoError THEN
  3592.             fKind := ValueCell
  3593.         ELSE
  3594.             fKind := ErrorCell;
  3595.         END
  3596.     ELSE
  3597.         fKind := TextCell;
  3598.     END;
  3599.  
  3600. {--------------------------------------------------------------------------------------------------}
  3601. {$S ARes}
  3602.  
  3603. PROCEDURE TCell.GetAsString(VAR theString: Str255);
  3604.  
  3605.     BEGIN
  3606.     theString := fFormula;
  3607.     END;
  3608.  
  3609. {--------------------------------------------------------------------------------------------------}
  3610. {$S AWriteFile}
  3611.  
  3612. FUNCTION TCell.GetDiskSize(infoRecordOnly: BOOLEAN): INTEGER;
  3613.  
  3614.     VAR
  3615.         cellSize:            INTEGER;
  3616.  
  3617.     BEGIN
  3618.     cellSize := SIZEOF(CellDiskInfo) - SIZEOF(Str255) + LENGTH(fFormula) + 1;
  3619.     IF NOT infoRecordOnly THEN
  3620.         cellSize := cellSize + (fReferences.fSize + fDependents.fSize + 1) * SIZEOF(Point);
  3621.     GetDiskSize := cellSize;
  3622.     END;
  3623.  
  3624. {--------------------------------------------------------------------------------------------------}
  3625. {$S ARes}
  3626.  
  3627. PROCEDURE TCell.GetValueAsString(VAR theString: Str255);
  3628.  
  3629.     BEGIN
  3630.     CASE fKind OF
  3631.         TextCell:
  3632.             theString := fFormula;
  3633.         ValueCell:
  3634.             BEGIN
  3635.             IF fValueString = '' THEN
  3636.                 ValueToString;
  3637.             theString := fValueString;
  3638.             END;
  3639.         ErrorCell:
  3640.             BEGIN
  3641.             NumToString(ORD(fError), theString);
  3642.             theString := CONCAT('**ERROR ', theString);
  3643.             END;
  3644.         OTHERWISE
  3645.             theString := '';
  3646.     END;
  3647.     END;
  3648.  
  3649. {--------------------------------------------------------------------------------------------------}
  3650. {$S AFields}
  3651.  
  3652. PROCEDURE TCell.Fields(PROCEDURE DoToField(fieldName: Str255;
  3653.                                            fieldAddr: Ptr;
  3654.                                            fieldType: INTEGER)); OVERRIDE;
  3655.  
  3656.     VAR
  3657.         aString:            Str255;
  3658.  
  3659.     BEGIN
  3660.     DoToField('TCell', NIL, bClass);
  3661.     DoToField('fDeleted', @fDeleted, bBoolean);
  3662.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  3663.     DoToField('fDependents', @fDependents, bObject);
  3664.     DoToField('fReferences', @fReferences, bObject);
  3665.     DoToField('fRow', @fRow, bByte);
  3666.     DoToField('fColumn', @fColumn, bByte);
  3667.     CASE fKind OF
  3668.         EmptyCell:
  3669.             aString := 'Empty';
  3670.         ValueCell:
  3671.             aString := 'Value';
  3672.         TextCell:
  3673.             aString := 'Text';
  3674.         ErrorCell:
  3675.             aString := 'Error';
  3676.     END;
  3677.     DoToField('fKind', @aString, bString);
  3678.     CASE fError OF
  3679.         NoError:
  3680.             aString := 'None';
  3681.         MissingRightParen:
  3682.             aString := 'Missing right parenthesis';
  3683.         SelfReference:
  3684.             aString := 'Self reference';
  3685.         ErrorCellReference:
  3686.             aString := 'Reference to error cell';
  3687.         BadNumber:
  3688.             aString := 'Bad number';
  3689.         IllegalCharacter:
  3690.             aString := 'Illegal character';
  3691.         BadCellReference:
  3692.             aString := 'Bad cell reference';
  3693.         GarbageAtEnd:
  3694.             aString := 'Garbage at end';
  3695.     END;
  3696.     DoToField('fError', @aString, bString);
  3697.     DoToField('fValueString', @fValueString, bString);
  3698.     DoToField('fFormula', @fFormula, bString);
  3699.     DoToField('fEvaluating', @fEvaluating, bBoolean);
  3700.     DoToField('fCalculating', @fCalculating, bBoolean);
  3701.     INHERITED Fields(DoToField);
  3702.     END;
  3703.  
  3704. {--------------------------------------------------------------------------------------------------}
  3705. {$S AFields}
  3706.  
  3707. PROCEDURE TCell.GetInspectorName(VAR inspectorName: Str255); OVERRIDE;
  3708.  
  3709.     VAR
  3710.         aString, titleString: Str255;
  3711.  
  3712.     BEGIN
  3713.     IF IsObject(fCalcDocument.fColumnsView) THEN
  3714.         BEGIN
  3715.         fCalcDocument.fColumnsView.CoordToString(fColumn, aString);
  3716.         NumToString(fRow, inspectorName);
  3717.         fCalcDocument.GetInspectorName(titleString);
  3718.         inspectorName := CONCAT(titleString, ' ', aString, inspectorName);
  3719.         END;
  3720.     END;
  3721.  
  3722. {--------------------------------------------------------------------------------------------------}
  3723. {$S ARes}
  3724.  
  3725. PROCEDURE TCell.invalidate;
  3726.  
  3727.     VAR
  3728.         aCell:                GridCell;
  3729.  
  3730.     BEGIN
  3731.     aCell.h := fColumn;
  3732.     aCell.v := fRow;
  3733.     fCalcDocument.fCellsView.InvalidateCell(aCell);
  3734.     END;
  3735.  
  3736. {--------------------------------------------------------------------------------------------------}
  3737. {$S ARes}
  3738.  
  3739. FUNCTION TCell.IsEmpty: BOOLEAN;
  3740.  
  3741.     BEGIN
  3742.     IsEmpty := (fKind = EmptyCell) & (LENGTH(fFormula) = 0);
  3743.     END;
  3744.  
  3745. {--------------------------------------------------------------------------------------------------}
  3746. {$S AReadFile}
  3747.  
  3748. PROCEDURE TCell.ReadFromDisk(theRefNum: INTEGER);
  3749.  
  3750.     VAR
  3751.         cellLength:         INTEGER;
  3752.         cellInfo:            CellDiskInfo;
  3753.         referencedCell:     TCell;
  3754.         refRow:             RowNumber;
  3755.         refColumn:            ColumnNumber;
  3756.         refIndex:            INTEGER;
  3757.  
  3758.     BEGIN
  3759.     ReadBytes(theRefNum, SIZEOF(cellLength), @cellLength);
  3760.     ReadBytes(theRefNum, cellLength, @cellInfo);
  3761.  
  3762.     WITH cellInfo DO
  3763.         BEGIN
  3764.         fKind := kind;
  3765.         fError := error;
  3766.         fValue := value;
  3767.         fFormula := formula;
  3768.  
  3769.         FOR refIndex := 1 TO noOfReferences DO
  3770.             BEGIN
  3771.             ReadCellCoordinate(theRefNum, refRow, refColumn);
  3772.             referencedCell := fCalcDocument.GetCell(refRow, refColumn);
  3773.             fReferences.InsertLast(referencedCell);
  3774.             referencedCell.fDependents.InsertLast(SELF);
  3775.             END;
  3776.         END;
  3777.     END;
  3778.  
  3779. {--------------------------------------------------------------------------------------------------}
  3780. {$S AClipBoard}
  3781.  
  3782. PROCEDURE TCell.ReadFromScrap(theScrap: Handle;
  3783.                               VAR scrapOffset: LONGINT);
  3784.  
  3785.     VAR
  3786.         cellLength:         INTEGER;
  3787.         cellInfo:            CellDiskInfo;
  3788.         referencedCell:     TCell;
  3789.         cellCoord:            Point;
  3790.         refIndex:            INTEGER;
  3791.  
  3792.     BEGIN
  3793.     ReadScrap(theScrap, scrapOffset, @cellLength, SIZEOF(cellLength));
  3794.     ReadScrap(theScrap, scrapOffset, @cellInfo, cellLength);
  3795.  
  3796.     WITH cellInfo DO
  3797.         BEGIN
  3798.         fKind := kind;
  3799.         fError := error;
  3800.         fValue := value;
  3801.         fFormula := formula;
  3802.  
  3803.         FOR refIndex := 1 TO noOfReferences DO
  3804.             BEGIN
  3805.             ReadScrap(theScrap, scrapOffset, @cellCoord, SIZEOF(cellCoord));
  3806.             referencedCell := fCalcDocument.GetCell(cellCoord.v, cellCoord.h);
  3807.             fReferences.InsertLast(referencedCell);
  3808.             referencedCell.fDependents.InsertLast(SELF);
  3809.             END;
  3810.         END;
  3811.     END;
  3812.  
  3813. {--------------------------------------------------------------------------------------------------}
  3814. {$S ARes}
  3815.  
  3816. PROCEDURE TCell.Recalculate(forceAutomatic: BOOLEAN;
  3817.                             setDependents: BOOLEAN);
  3818.  
  3819. {--------------------------------------------------------------------------------------------------}
  3820.  
  3821.     PROCEDURE RemoveDependent(theObject: TObject);
  3822.  
  3823.         BEGIN
  3824.         TCell(theObject).fDependents.Delete(TObject(SELF));
  3825.         END;
  3826.  
  3827. {--------------------------------------------------------------------------------------------------}
  3828.  
  3829.     PROCEDURE CalculateCell(theObject: TObject);
  3830.  
  3831.         VAR
  3832.             theCell:            TCell;
  3833.             oldValue:            ValueType;
  3834.             oldKind:            KindOfCell;
  3835.             shouldInvalidate:    BOOLEAN;
  3836.             wasLocked:            BOOLEAN;
  3837.  
  3838.         BEGIN
  3839.         theCell := TCell(theObject);
  3840.         
  3841.         wasLocked := theCell.Lock(TRUE);
  3842.         
  3843.         WITH theCell DO
  3844.             BEGIN
  3845.             IF NOT fCalculating THEN
  3846.                 BEGIN
  3847.                 fCalculating := TRUE;                    { prevent circular reference loop }
  3848.                 fValueString := '';
  3849.                 oldValue := fValue;
  3850.                 oldKind := fKind;
  3851.                 EvaluateFormula(setDependents);
  3852.                 shouldInvalidate := (oldValue <> fValue) | (oldKind <> fKind);
  3853.                 IF shouldInvalidate | setDependents THEN
  3854.                     BEGIN
  3855.                     setDependents := FALSE;
  3856.                     IF shouldInvalidate THEN
  3857.                         theCell.invalidate;
  3858.                     IF forceAutomatic | fCalcDocument.IsAutoCalc THEN
  3859.                         fDependents.Each(CalculateCell);
  3860.                     END;
  3861.                 fCalculating := FALSE;
  3862.                 END;
  3863.             END;
  3864.             
  3865.         wasLocked := theCell.Lock(wasLocked);
  3866.         END;
  3867.  
  3868.     BEGIN
  3869.     IF setDependents THEN
  3870.         BEGIN
  3871.         fReferences.Each(RemoveDependent);
  3872.         fReferences.DeleteAll;
  3873.         END;
  3874.     CalculateCell(TObject(SELF));
  3875.     END;
  3876.  
  3877. {--------------------------------------------------------------------------------------------------}
  3878. {$S ARes}
  3879.  
  3880. PROCEDURE TCell.SetDeleteState(deleted: BOOLEAN);
  3881.  
  3882.     BEGIN
  3883.     fDeleted := deleted;
  3884.     END;
  3885.  
  3886. {--------------------------------------------------------------------------------------------------}
  3887. {$S ARes}
  3888.  
  3889. PROCEDURE TCell.SetToString(theString: Str255);
  3890.  
  3891.     VAR
  3892.         theOldString:        Str255;
  3893.  
  3894.     BEGIN
  3895.     GetAsString(theOldString);
  3896.     IF theString <> theOldString THEN
  3897.         BEGIN
  3898.         fFormula := theString;
  3899.         fKind := EmptyCell;                             { Force Recalculate to invalidate the cell }
  3900.         Recalculate(NOT kForceAutomatic, kSetDependents); { we want to set new dependents }
  3901.         END;
  3902.     END;
  3903.  
  3904. {--------------------------------------------------------------------------------------------------}
  3905. {$S ARes}
  3906.  
  3907. PROCEDURE TCell.ValueToString;
  3908.  { Fills fValueString with the string representation of the cell's value.
  3909.    The "general" format is complicated because we try to ensure that
  3910.    the string will fit within the cell's column width.  Thus we have
  3911.    to figure out the appropriate representation for the value. }
  3912.  
  3913.     VAR
  3914.         aString:            Str255;
  3915.         theFormat:            DecForm;
  3916.         d:                    Decimal;
  3917.         i:                    INTEGER;
  3918.         len:                INTEGER;
  3919.         sigDigits:            INTEGER;
  3920.         leftDigits:         INTEGER;
  3921.         rightDigits:        INTEGER;
  3922.         width:                INTEGER;
  3923.         digitWidth:         INTEGER;
  3924.         dotWidth:            INTEGER;
  3925.         eWidth:             INTEGER;
  3926.         minusWidth:         INTEGER;
  3927.         plusWidth:            INTEGER;
  3928.         aColumn:            TColumn;
  3929.         aValueType:         ValueType;
  3930.  
  3931.     BEGIN
  3932.     aColumn := fCalcDocument.GetColumn(fColumn);
  3933.     WITH aColumn DO
  3934.         CASE fFormat.fStyle OF
  3935.             General:
  3936.                 BEGIN
  3937.                 SetTheFont(fFormat.fFontNumber, fFormat.fFontSize, fFormat.fFontStyle);
  3938.                 digitWidth := CharWidth('0');
  3939.                 dotWidth := CharWidth('.');
  3940.                 eWidth := CharWidth('e');
  3941.                 minusWidth := CharWidth('-');
  3942.                 plusWidth := CharWidth('+');
  3943.                 width := fCalcDocument.fCellsView.GetColWidth(fColumn) - (kCellHBorder * 2);
  3944.  
  3945.                 theFormat := gGeneralFormat;
  3946.                 aValueType := fValue;
  3947.                 Num2Dec(theFormat, aValueType, d);
  3948.                 aString := d.sig;
  3949.                 len := LENGTH(aString);
  3950.  
  3951.                 IF d.sgn = 1 THEN
  3952.                     width := width - minusWidth;
  3953.  
  3954.                 IF d.exp > 0 THEN
  3955.                 { We've exceeded the precision of our value representation }
  3956.                     BEGIN
  3957.                     theFormat.Style := FloatDecimal;
  3958.                     { account for '.' and '+e99' }
  3959.                     width := width - dotWidth - CharWidth('+') - eWidth - digitWidth - digitWidth;
  3960.                     theFormat.digits := Min(kValuePrecision, width DIV digitWidth);
  3961.                     END
  3962.                 ELSE
  3963.                     BEGIN
  3964.  
  3965.                     { determine number of significant digits }
  3966.                     sigDigits := 1;                     { in case all digits are zero }
  3967.                     FOR i := len DOWNTO 2 DO
  3968.                         IF aString[i] <> '0' THEN
  3969.                             BEGIN
  3970.                             sigDigits := i;
  3971.                             LEAVE;
  3972.                             END;
  3973.  
  3974.                     leftDigits := kValuePrecision + d.exp;
  3975.                     rightDigits := sigDigits - leftDigits;
  3976.  
  3977.                     IF leftDigits < sigDigits THEN
  3978.                         width := width - dotWidth;        { account for decimal point }
  3979.  
  3980.                     IF leftDigits * digitWidth > width THEN
  3981.                         BEGIN
  3982.                         { We must convert to scientific notation }
  3983.  
  3984.                         { account for decimal point and 'e9' }
  3985.                         width := width - dotWidth - eWidth - digitWidth;
  3986.  
  3987.      { For positive numbers, SANE puts a space (' ') before
  3988.       the first significant digit. }
  3989.                         IF d.sgn <> 1 THEN
  3990.                             width := width - CharWidth(' ');
  3991.                         IF d.exp < - kValuePrecision THEN
  3992.                             width := width - minusWidth
  3993.                         ELSE
  3994.                             width := width - plusWidth;
  3995.                         IF leftDigits > 10 THEN
  3996.                             width := width - digitWidth; { account for double-digit exponents }
  3997.  
  3998.                         theFormat.Style := FloatDecimal;
  3999.                         theFormat.digits := Min(sigDigits, width DIV digitWidth);
  4000.                         END
  4001.                     ELSE
  4002.                         BEGIN
  4003.                         theFormat.Style := FixedDecimal;
  4004.                         theFormat.digits := Min((width - (leftDigits * digitWidth) - dotWidth) DIV
  4005.                                                 digitWidth, rightDigits);
  4006.                         IF theFormat.digits < 0 THEN
  4007.                             theFormat.digits := 0;
  4008.                         END;
  4009.                     END;
  4010.                 END;
  4011.             DecimalStyle:
  4012.                 theFormat := gDecimalFormat;
  4013.             NoDecimal:
  4014.                 theFormat := gNoDecimalFormat;
  4015.             Scientific:
  4016.                 theFormat := gScientificFormat;
  4017.         END;
  4018.  
  4019.     aValueType := fValue;
  4020.     Num2Str(theFormat, aValueType, DecStr(aString));
  4021.     IF aString[1] = ' ' THEN
  4022.         Delete(aString, 1, 1);                            { Remove leading space }
  4023.     fValueString := Copy(aString, 1, Min(kMaxValueLength, LENGTH(aString)));
  4024.     END;
  4025.  
  4026. {--------------------------------------------------------------------------------------------------}
  4027. {$S AWriteFile}
  4028.  
  4029. PROCEDURE TCell.WriteToDisk(theRefNum: INTEGER);
  4030.  
  4031.     VAR
  4032.         cellInfo:            CellDiskInfo;
  4033.         cellLength:         INTEGER;
  4034.  
  4035. {--------------------------------------------------------------------------------------------------}
  4036.  
  4037.     PROCEDURE WriteCellCoordinate(theObject: TObject);
  4038.  
  4039.         VAR
  4040.             cellCoordinate:     Point;
  4041.  
  4042.         BEGIN
  4043.         cellCoordinate.v := TCell(theObject).fRow;
  4044.         cellCoordinate.h := TCell(theObject).fColumn;
  4045.         WriteBytes(theRefNum, SIZEOF(cellCoordinate), @cellCoordinate);
  4046.         END;
  4047.  
  4048.     BEGIN
  4049.     WriteCellCoordinate(TObject(SELF));
  4050.     cellLength := GetDiskSize(TRUE);                    { don't include ref's & dependents }
  4051.     WriteBytes(theRefNum, SIZEOF(cellLength), @cellLength);
  4052.     WITH cellInfo DO
  4053.         BEGIN
  4054.         kind := fKind;
  4055.         error := fError;
  4056.         value := fValue;
  4057.         noOfReferences := fReferences.fSize;
  4058.         formula := fFormula;
  4059.  
  4060.         WriteBytes(theRefNum, cellLength, @cellInfo);
  4061.  
  4062.         fReferences.Each(WriteCellCoordinate);
  4063.         END;
  4064.     END;
  4065.  
  4066. {--------------------------------------------------------------------------------------------------}
  4067. {$S AClipBoard}
  4068.  
  4069. PROCEDURE TCell.WriteToScrap(theScrap: Handle;
  4070.                              VAR scrapOffset: LONGINT);
  4071.  
  4072.     VAR
  4073.         cellInfo:            CellDiskInfo;
  4074.         cellLength:         INTEGER;
  4075.  
  4076. {--------------------------------------------------------------------------------------------------}
  4077.  
  4078.     PROCEDURE WriteCellCoordinate(theObject: TObject);
  4079.  
  4080.         VAR
  4081.             cellCoordinate:     Point;
  4082.  
  4083.         BEGIN
  4084.         cellCoordinate.v := TCell(theObject).fRow;
  4085.         cellCoordinate.h := TCell(theObject).fColumn;
  4086.         WriteScrap(theScrap, scrapOffset, @cellCoordinate, SIZEOF(cellCoordinate));
  4087.         END;
  4088.  
  4089.     BEGIN
  4090.     WriteCellCoordinate(TObject(SELF));
  4091.     cellLength := GetDiskSize(TRUE);                    { don't include ref's & dependents }
  4092.     WriteScrap(theScrap, scrapOffset, @cellLength, SIZEOF(cellLength));
  4093.     WITH cellInfo DO
  4094.         BEGIN
  4095.         kind := fKind;
  4096.         error := fError;
  4097.         value := fValue;
  4098.         noOfReferences := 0;                            { fReferences.fSize }
  4099.         formula := fFormula;
  4100.  
  4101.         WriteScrap(theScrap, scrapOffset, @cellInfo, cellLength);
  4102.         END;
  4103.     END;
  4104.  
  4105. {***************************************************************************************************
  4106.     T C a l c S e l e c t C o m m a n d
  4107. ***************************************************************************************************}
  4108. {$S ASelCommand}
  4109.  
  4110. PROCEDURE TCalcSelectCommand.ICalcSelectCommand(itsDocument: TCalcDocument;
  4111.                                                 itsView: TGridView;
  4112.                                                 theShiftKey, theCmdKey: BOOLEAN);
  4113.  
  4114.     BEGIN
  4115.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4116.     fCalcDocument := itsDocument;
  4117.     itsDocument.fEntryView.EditMode(FALSE);
  4118.     END;
  4119.  
  4120. {--------------------------------------------------------------------------------------------------}
  4121. {$S ADoCommand}
  4122.  
  4123. PROCEDURE TCalcSelectCommand.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4124.  
  4125.     VAR
  4126.         r:                    Rect;
  4127.  
  4128.     BEGIN
  4129.     IF fGridView.CanSelectCell(clickedCell) THEN
  4130.         BEGIN
  4131.         Pt2Rect(fAnchorCell, clickedCell, r);
  4132.         r.right := r.right + 1;
  4133.         r.bottom := r.bottom + 1;
  4134.         RectRgn(fThisSelection, r);
  4135.         IF fCmdKey THEN
  4136.             IF fDeselecting THEN
  4137.                 DiffRgn(fPrevSelection, fThisSelection, fThisSelection)
  4138.             ELSE
  4139.                 UnionRgn(fPrevSelection, fThisSelection, fThisSelection);
  4140.         END;
  4141.     END;
  4142.  
  4143. {***************************************************************************************************
  4144.     T R o W S e l e c t o r
  4145. ***************************************************************************************************}
  4146. {$S ASelCommand}
  4147.  
  4148. PROCEDURE TRowSelector.IRowSelector(itsDocument: TCalcDocument;
  4149.                                     itsView: TGridView;
  4150.                                     theShiftKey, theCmdKey: BOOLEAN);
  4151.  
  4152.     VAR
  4153.         aCellSelector:        TCalcSelectCommand;
  4154.  
  4155.     BEGIN
  4156.     fCalcDocument := itsDocument;
  4157.     IF fCalcDocument.fSelectionType <> RowSelection THEN
  4158.         theCmdKey := FALSE;
  4159.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4160.  
  4161.     NEW(aCellSelector);
  4162.     FailNIL(aCellSelector);
  4163.     aCellSelector.ICalcSelectCommand(itsDocument, itsDocument.fCellsView, theShiftKey, theCmdKey);
  4164.     fCellSelector := aCellSelector;
  4165.     END;
  4166.  
  4167. {--------------------------------------------------------------------------------------------------}
  4168. {$S ARes}
  4169.  
  4170. PROCEDURE TRowSelector.Free; OVERRIDE;
  4171.  
  4172.     BEGIN
  4173.     FreeIfObject(fCellSelector);
  4174.     fCellSelector := NIL;
  4175.  
  4176.     INHERITED Free;
  4177.     END;
  4178.  
  4179. {--------------------------------------------------------------------------------------------------}
  4180. {$S ADoCommand}
  4181.  
  4182. PROCEDURE TRowSelector.ComputeAnchorCell(VAR clickedCell: GridCell); OVERRIDE;
  4183.  
  4184.     BEGIN
  4185.     INHERITED ComputeAnchorCell(clickedCell);
  4186.     fAnchorCell.h := 1;
  4187.  
  4188.     clickedCell.h := 1;
  4189.     fCellSelector.ComputeAnchorCell(clickedCell);
  4190.     END;
  4191.  
  4192. {--------------------------------------------------------------------------------------------------}
  4193. {$S ADoCommand}
  4194.  
  4195. PROCEDURE TRowSelector.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4196.  
  4197.     VAR
  4198.         r:                    Rect;
  4199.  
  4200.     BEGIN
  4201.     clickedCell.h := fGridView.fNumOfCols;
  4202.     INHERITED ComputeNewSelection(clickedCell);
  4203.  
  4204.     clickedCell.h := fCalcDocument.fNoOfColumns;
  4205.     fCellSelector.ComputeNewSelection(clickedCell);
  4206.     END;
  4207.  
  4208. {--------------------------------------------------------------------------------------------------}
  4209. {$S ADoCommand}
  4210.  
  4211. PROCEDURE TRowSelector.DoIt; OVERRIDE;
  4212.  
  4213.     BEGIN
  4214.     INHERITED DoIt;
  4215.     fCellSelector.DoIt;
  4216.     END;
  4217.  
  4218. {--------------------------------------------------------------------------------------------------}
  4219. {$S ADoCommand}
  4220.  
  4221. FUNCTION TRowSelector.TrackMouse(aTrackPhase: TrackPhase;
  4222.                                  VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4223.                                  mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4224.  
  4225.     VAR
  4226.         clickedCell:        GridCell;
  4227.  
  4228.     BEGIN
  4229.     IF mouseDidMove THEN
  4230.         BEGIN
  4231.         clickedCell := fGridView.VPointToCell(nextPoint);
  4232.         IF aTrackPhase = TrackPress THEN
  4233.             BEGIN
  4234.             ComputeAnchorCell(clickedCell);
  4235.             IF fCmdKey THEN
  4236.                 BEGIN
  4237.                 fDeselecting := PtInRgn(fAnchorCell, fGridView.fSelections);
  4238.                 fCellSelector.fDeselecting := fDeselecting;
  4239.                 END;
  4240.             END;
  4241.  
  4242.         IF LONGINT(clickedCell) <> LONGINT(fPrevCell) THEN
  4243.             BEGIN
  4244.             ComputeNewSelection(clickedCell);
  4245.             HighlightNewSelection;
  4246.             fCellSelector.HighlightNewSelection;
  4247.  
  4248.             CopyRgn(fThisSelection, fPrevSelection);
  4249.             fPrevCell := clickedCell;
  4250.             WITH fCellSelector DO
  4251.                 BEGIN
  4252.                 CopyRgn(fThisSelection, fPrevSelection);
  4253.                 fPrevCell := clickedCell;
  4254.                 END;
  4255.             END;
  4256.         END;
  4257.     TrackMouse := SELF;
  4258.     END;
  4259.  
  4260. {***************************************************************************************************
  4261.     T C o l u m n S e l e c t o r
  4262. ***************************************************************************************************}
  4263. {$S ASelCommand}
  4264.  
  4265. PROCEDURE TColumnSelector.IColumnSelector(itsDocument: TCalcDocument;
  4266.                                           itsView: TGridView;
  4267.                                           theShiftKey, theCmdKey: BOOLEAN);
  4268.  
  4269.     VAR
  4270.         aCellSelector:        TCalcSelectCommand;
  4271.  
  4272.     BEGIN
  4273.     fCalcDocument := itsDocument;
  4274.     IF fCalcDocument.fSelectionType <> ColumnSelection THEN
  4275.         theCmdKey := FALSE;
  4276.     ICellSelectCommand(itsView, theShiftKey, theCmdKey);
  4277.  
  4278.     NEW(aCellSelector);
  4279.     FailNIL(aCellSelector);
  4280.     aCellSelector.ICalcSelectCommand(itsDocument, itsDocument.fCellsView, theShiftKey, theCmdKey);
  4281.     fCellSelector := aCellSelector;
  4282.     END;
  4283.  
  4284. {--------------------------------------------------------------------------------------------------}
  4285. {$S ARes}
  4286.  
  4287. PROCEDURE TColumnSelector.Free; OVERRIDE;
  4288.  
  4289.     BEGIN
  4290.     FreeIfObject(fCellSelector);
  4291.     fCellSelector := NIL;
  4292.  
  4293.     INHERITED Free;
  4294.     END;
  4295.  
  4296. {--------------------------------------------------------------------------------------------------}
  4297. {$S ADoCommand}
  4298.  
  4299. PROCEDURE TColumnSelector.ComputeAnchorCell(VAR clickedCell: GridCell); OVERRIDE;
  4300.  
  4301.     BEGIN
  4302.     INHERITED ComputeAnchorCell(clickedCell);
  4303.     fAnchorCell.v := 1;
  4304.  
  4305.     clickedCell.v := 1;
  4306.     fCellSelector.ComputeAnchorCell(clickedCell);
  4307.     END;
  4308.  
  4309. {--------------------------------------------------------------------------------------------------}
  4310. {$S ADoCommand}
  4311.  
  4312. PROCEDURE TColumnSelector.ComputeNewSelection(VAR clickedCell: GridCell); OVERRIDE;
  4313.  
  4314.     VAR
  4315.         r:                    Rect;
  4316.  
  4317.     BEGIN
  4318.     clickedCell.v := fGridView.fNumOfRows;
  4319.     INHERITED ComputeNewSelection(clickedCell);
  4320.  
  4321.     clickedCell.v := fCalcDocument.fNoOfRows;
  4322.     fCellSelector.ComputeNewSelection(clickedCell);
  4323.     END;
  4324.  
  4325. {--------------------------------------------------------------------------------------------------}
  4326. {$S ADoCommand}
  4327.  
  4328. PROCEDURE TColumnSelector.DoIt; OVERRIDE;
  4329.  
  4330.     BEGIN
  4331.     INHERITED DoIt;
  4332.     fCellSelector.DoIt;
  4333.     END;
  4334.  
  4335. {--------------------------------------------------------------------------------------------------}
  4336. {$S ADoCommand}
  4337.  
  4338. FUNCTION TColumnSelector.TrackMouse(aTrackPhase: TrackPhase;
  4339.                                     VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4340.                                     mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4341.  
  4342.     VAR
  4343.         clickedCell:        GridCell;
  4344.  
  4345.     BEGIN
  4346.     IF mouseDidMove THEN
  4347.         BEGIN
  4348.         clickedCell := fGridView.VPointToCell(nextPoint);
  4349.         IF aTrackPhase = TrackPress THEN
  4350.             BEGIN
  4351.             ComputeAnchorCell(clickedCell);
  4352.             IF fCmdKey THEN
  4353.                 BEGIN
  4354.                 fDeselecting := PtInRgn(fAnchorCell, fGridView.fSelections);
  4355.                 fCellSelector.fDeselecting := fDeselecting;
  4356.                 END;
  4357.             END;
  4358.  
  4359.         IF LONGINT(clickedCell) <> LONGINT(fPrevCell) THEN
  4360.             BEGIN
  4361.             ComputeNewSelection(clickedCell);
  4362.             HighlightNewSelection;
  4363.             fCellSelector.HighlightNewSelection;
  4364.  
  4365.             CopyRgn(fThisSelection, fPrevSelection);
  4366.             fPrevCell := clickedCell;
  4367.             WITH fCellSelector DO
  4368.                 BEGIN
  4369.                 CopyRgn(fThisSelection, fPrevSelection);
  4370.                 fPrevCell := clickedCell;
  4371.                 END;
  4372.             END;
  4373.         END;
  4374.     TrackMouse := SELF;
  4375.     END;
  4376.  
  4377. {***************************************************************************************************
  4378.     T C o l u m n F o r m a t t e r
  4379. ***************************************************************************************************}
  4380. {$S ASelCommand}
  4381.  
  4382. PROCEDURE TColumnFormatter.IFormatter(itsDocument: TCalcDocument;
  4383.                                       itsCommand: INTEGER);
  4384.  
  4385.     VAR
  4386.         fi:            FailInfo;
  4387.  
  4388.     PROCEDURE HdlAllocationFailure(error: OSErr; message: LONGINT);
  4389.         
  4390.         BEGIN
  4391.         Free;
  4392.         END;
  4393.  
  4394. {--------------------------------------------------------------------------------------------------}
  4395.  
  4396.     PROCEDURE SaveFormat(aCell: GridCell);
  4397.  
  4398.         VAR
  4399.             theColumn:            TColumn;
  4400.  
  4401.         BEGIN
  4402.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4403.         theColumn.fOldFormat := theColumn.fFormat;
  4404.         END;
  4405.  
  4406.     BEGIN
  4407.     ICommand(itsCommand, itsDocument, itsDocument.fCellsView,
  4408.              itsDocument.fColumnsView.GetScroller(TRUE));
  4409.     fCalcDocument := itsDocument;
  4410.     CatchFailures(fi, HdlAllocationFailure);
  4411.     fSelection := MakeNewRgn;                            { copy the current selection region }
  4412.     CopyRgn(itsDocument.fColumnsView.fSelections, fSelection);
  4413.     Success(fi);
  4414.     fCalcDocument.fColumnsView.EachSelectedCellDo(SaveFormat);
  4415.     END;
  4416.  
  4417. {--------------------------------------------------------------------------------------------------}
  4418. {$S ADoCommand}
  4419.  
  4420. PROCEDURE TColumnFormatter.DoIt; OVERRIDE;
  4421.  
  4422.     PROCEDURE SetFormat(aCell: GridCell);
  4423.  
  4424.         VAR
  4425.             theColumn:            TColumn;
  4426.  
  4427.         BEGIN
  4428.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4429.         WITH theColumn.fFormat DO
  4430.             CASE fCmdNumber OF
  4431.                 cGeneral:
  4432.                     fStyle := General;
  4433.                 cNoDecimal:
  4434.                     fStyle := NoDecimal;
  4435.                 cDecimal:
  4436.                     fStyle := DecimalStyle;
  4437.                 cScientific:
  4438.                     fStyle := Scientific;
  4439.                 cSystemJustify:
  4440.                     fJustification := teJustSystem;
  4441.                 cForceLeftJustify:
  4442.                     fJustification := teForceLeft;
  4443.                 cRightJustify:
  4444.                     fJustification := TEJustRight;
  4445.                 cCenter:
  4446.                     fJustification := TEJustCenter;
  4447.             END;
  4448.         END;
  4449.  
  4450.     BEGIN
  4451.     fCalcDocument.fColumnsView.EachSelectedCellDo(SetFormat);
  4452.     IF (fCmdNumber >= cGeneral) & (fCmdNumber <= cScientific) THEN { Style change }
  4453.         fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4454.     fCalcDocument.fCellsView.InvalidateSelection;
  4455.     END;
  4456.  
  4457. {--------------------------------------------------------------------------------------------------}
  4458. {$S ADoCommand}
  4459.  
  4460. PROCEDURE TColumnFormatter.Free; OVERRIDE;
  4461.  
  4462.     BEGIN
  4463.     IF fSelection <> NIL THEN
  4464.         DisposeRgn(fSelection);
  4465.     fSelection := NIL;
  4466.  
  4467.     INHERITED Free;
  4468.     END;
  4469.  
  4470. {--------------------------------------------------------------------------------------------------}
  4471. {$S ADoCommand}
  4472.  
  4473. PROCEDURE TColumnFormatter.RedoIt; OVERRIDE;
  4474.  
  4475.     BEGIN
  4476.     fCalcDocument.fColumnsView.ReSelect(fSelection);
  4477.     DoIt;
  4478.     END;
  4479.  
  4480. {--------------------------------------------------------------------------------------------------}
  4481. {$S ADoCommand}
  4482.  
  4483. PROCEDURE TColumnFormatter.UndoIt; OVERRIDE;
  4484.  
  4485.     PROCEDURE RestoreFormat(aCell: GridCell);
  4486.  
  4487.         VAR
  4488.             theColumn:            TColumn;
  4489.  
  4490.         BEGIN
  4491.         theColumn := fCalcDocument.GetColumn(aCell.h);
  4492.         theColumn.fFormat := theColumn.fOldFormat;
  4493.         END;
  4494.  
  4495.     BEGIN
  4496.     WITH fCalcDocument.fColumnsView DO
  4497.         BEGIN
  4498.         ReSelect(fSelection);
  4499.         EachSelectedCellDo(RestoreFormat);
  4500.         END;
  4501.     IF (fCmdNumber >= cGeneral) & (fCmdNumber <= cScientific) THEN { Style change }
  4502.         fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4503.     fCalcDocument.fCellsView.InvalidateSelection;
  4504.     END;
  4505.  
  4506. {--------------------------------------------------------------------------------------------------}
  4507. {$S AFields}
  4508.  
  4509. PROCEDURE TColumnFormatter.Fields(PROCEDURE DoToField(fieldName: Str255;
  4510.                                                       fieldAddr: Ptr;
  4511.                                                       fieldType: INTEGER)); OVERRIDE;
  4512.  
  4513.     BEGIN
  4514.     DoToField('TColumnFormatter', NIL, bClass);
  4515.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  4516.     INHERITED Fields(DoToField);
  4517.     END;
  4518.  
  4519. {***************************************************************************************************
  4520.     T C o l u m n S i z e r
  4521. ***************************************************************************************************}
  4522. {$S ASelCommand}
  4523.  
  4524. PROCEDURE TColumnSizer.IColumnSizer(itsDocument: TCalcDocument;
  4525.                                     c: ColumnNumber);
  4526.  
  4527.     VAR
  4528.         colRect:            VRect;
  4529.  
  4530.     BEGIN
  4531.     ICommand(cSizeColumn, itsDocument, itsDocument.fCellsView,
  4532.              itsDocument.fColumnsView.GetScroller(TRUE));
  4533.     fConstrainsMouse := TRUE;
  4534.     fCalcDocument := itsDocument;
  4535.     fCellsView := itsDocument.fCellsView;
  4536.     fColumn := itsDocument.GetColumn(c);
  4537.     fNewWidth := fCellsView.GetColWidth(fColumn.fNumber);
  4538.     fOldWidth := fNewWidth;
  4539.     fCellsView.ColToVRect(fColumn.fNumber, 1, colRect);
  4540.     fLeftEdge := colRect.left;
  4541.     fViewConstrain := FALSE;                            { So that rightmost column can grow }
  4542.     END;
  4543.  
  4544. {--------------------------------------------------------------------------------------------------}
  4545. {$S ADoCommand}
  4546.  
  4547. FUNCTION TColumnSizer.TrackMouse(aTrackPhase: TrackPhase;
  4548.                                  VAR anchorPoint, previousPoint, nextPoint: VPoint;
  4549.                                  mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
  4550.  
  4551.     BEGIN
  4552.     fNewWidth := Min(nextPoint.h - fLeftEdge, kTELength);
  4553.     fNewWidth := Max(fNewWidth, 10);
  4554.     TrackMouse := SELF;
  4555.     nextPoint.h := Min(nextPoint.h, fLeftEdge + kTELength);
  4556.     END;
  4557.  
  4558. {--------------------------------------------------------------------------------------------------}
  4559. {$S ADoCommand}
  4560.  
  4561. PROCEDURE TColumnSizer.TrackFeedback(anchorPoint, nextPoint: VPoint;
  4562.                                      turnItOn, mouseDidMove: BOOLEAN); OVERRIDE;
  4563.  
  4564.     VAR
  4565.         viewedRect:         Rect;
  4566.         pState:             PenState;
  4567.  
  4568.     BEGIN
  4569.     IF mouseDidMove THEN
  4570.         BEGIN
  4571.         GetPenState(pState);
  4572.         PenPat(black);
  4573.  
  4574.         fCellsView.GetQDExtent(viewedRect);
  4575.  
  4576.         MoveTo(Min(nextPoint.h, fLeftEdge + kTELength), viewedRect.top);
  4577.         Line(0, viewedRect.bottom - viewedRect.top);
  4578.         SetPenState(pState);
  4579.         END;
  4580.     END;
  4581.  
  4582. {--------------------------------------------------------------------------------------------------}
  4583. {$S ADoCommand}
  4584.  
  4585. PROCEDURE TColumnSizer.TrackConstrain(anchorPoint, previousPoint: VPoint;
  4586.                                       VAR nextPoint: VPoint); OVERRIDE;
  4587.  
  4588.     BEGIN
  4589.     IF nextPoint.h < fLeftEdge + 10 THEN
  4590.         nextPoint.h := fLeftEdge + 10
  4591.     ELSE
  4592.         nextPoint.h := Min(nextPoint.h, fLeftEdge + kTELength);
  4593.     END;
  4594.  
  4595. {--------------------------------------------------------------------------------------------------}
  4596. {$S ADoCommand}
  4597.  
  4598. PROCEDURE TColumnSizer.SetColumnWidth(newWidth: INTEGER);
  4599.  
  4600.     BEGIN
  4601.     IF newWidth > kTELength THEN
  4602.         BEGIN
  4603.         newWidth := kTELength;
  4604.         fNewWidth := kTELength;
  4605.         END
  4606.     ELSE IF newWidth < 10 THEN
  4607.         newWidth := 10;
  4608.  
  4609.     fCellsView.SetColWidth(fColumn.fNumber, 1, newWidth);
  4610.     fCalcDocument.fColumnsView.SetColWidth(fColumn.fNumber, 1, newWidth);
  4611.     fColumn.fWidth := newWidth;
  4612.     END;
  4613.  
  4614. {--------------------------------------------------------------------------------------------------}
  4615. {$S ADoCommand}
  4616.  
  4617. PROCEDURE TColumnSizer.DoIt; OVERRIDE;
  4618.  
  4619.     VAR
  4620.         minToSee:            Point;
  4621.         aRect:                VRect;
  4622.  
  4623.     BEGIN
  4624.     SetColumnWidth(fNewWidth);
  4625.  
  4626.     fCellsView.ColToVRect(fColumn.fNumber, 1, aRect);
  4627.     WITH aRect DO
  4628.         SetPt(minToSee, right - left, bottom - top);
  4629.     fCellsView.RevealRect(aRect, minToSee, TRUE);
  4630.  
  4631.     fCalcDocument.fColumnsView.ColToVRect(fColumn.fNumber, 1, aRect);
  4632.     WITH aRect DO
  4633.         SetPt(minToSee, right - left, bottom - top);
  4634.     fCalcDocument.fColumnsView.RevealRect(aRect, minToSee, TRUE);
  4635.     END;
  4636.  
  4637. {--------------------------------------------------------------------------------------------------}
  4638. {$S ADoCommand}
  4639.  
  4640. PROCEDURE TColumnSizer.UndoIt; OVERRIDE;
  4641.  
  4642.     BEGIN
  4643.     SetColumnWidth(fOldWidth);
  4644.     END;
  4645.  
  4646. {--------------------------------------------------------------------------------------------------}
  4647. {$S ADoCommand}
  4648.  
  4649. PROCEDURE TColumnSizer.RedoIt; OVERRIDE;
  4650.  
  4651.     BEGIN
  4652.     DoIt;
  4653.     END;
  4654.  
  4655. {--------------------------------------------------------------------------------------------------}
  4656. {$S AFields}
  4657.  
  4658. PROCEDURE TColumnSizer.Fields(PROCEDURE DoToField(fieldName: Str255;
  4659.                                                   fieldAddr: Ptr;
  4660.                                                   fieldType: INTEGER)); OVERRIDE;
  4661.  
  4662.     BEGIN
  4663.     DoToField('TColumnSizer', NIL, bClass);
  4664.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  4665.     DoToField('fCellsView', @fCellsView, bObject);
  4666.     DoToField('fLeftEdge', @fLeftEdge, bInteger);
  4667.     DoToField('fColumn', @fColumn, bObject);
  4668.     DoToField('fNewWidth', @fNewWidth, bInteger);
  4669.     DoToField('fOldWidth', @fOldWidth, bInteger);
  4670.     INHERITED Fields(DoToField);
  4671.     END;
  4672.  
  4673. {***************************************************************************************************
  4674.     T C a l c T y p i n g C o m m a n d
  4675. ***************************************************************************************************}
  4676. {$S ADoCommand}
  4677.  
  4678. PROCEDURE TCalcTypingCommand.ITETypingCommand(itsTEView: TTEView;
  4679.                                               itsFirstChar: CHAR); OVERRIDE;
  4680.  
  4681.     BEGIN
  4682.     fCellsView := TEntryView(itsTEView).fCalcDocument.fCellsView;
  4683.     fTargetCell := fCellsView.FirstSelectedCell;
  4684.     INHERITED ITETypingCommand(itsTEView, itsFirstChar);
  4685.     END;
  4686.  
  4687. {--------------------------------------------------------------------------------------------------}
  4688. {$S ARes}
  4689.  
  4690. PROCEDURE TCalcTypingCommand.AddCharacter(aChar: CHAR); OVERRIDE;
  4691. { Switch the entry view from left to right justification when the typed characters overflow the
  4692.   entry box, and switch back to left justification if the text shrinks enough }
  4693.  
  4694.     VAR
  4695.         selRight:            INTEGER;
  4696.  
  4697. {--------------------------------------------------------------------------------------------------}
  4698.  
  4699.     FUNCTION AddCharWidths: INTEGER;
  4700.  
  4701.         VAR
  4702.             aString:            Str255;
  4703.  
  4704.         BEGIN
  4705.         GetIText(fHTE^^.hText, aString);
  4706.         AddCharWidths := StringWidth(aString);
  4707.         END;
  4708.  
  4709.     BEGIN
  4710.     IF (aChar <> chBackspace) & (fTEView.fJustification = TEJustLeft) THEN
  4711.         BEGIN
  4712.         selRight := fHTE^^.selRect.right;
  4713.         IF (selRight < 0) | (selRight > fHTE^^.destRect.right) THEN
  4714.             selRight := fHTE^^.selPoint.h;
  4715.         IF selRight + CharWidth(aChar) > fHTE^^.destRect.right THEN
  4716.             fTEView.SetJustification(TEJustRight, kDontRedraw);
  4717.         END;
  4718.  
  4719.     INHERITED AddCharacter(aChar);
  4720.  
  4721.     IF (aChar = chBackspace) & (fTEView.fJustification = TEJustRight) THEN
  4722.         IF AddCharWidths < LengthRect(fHTE^^.destRect, h) THEN
  4723.             fTEView.SetJustification(TEJustLeft, kRedraw);
  4724.     END;
  4725.  
  4726. {--------------------------------------------------------------------------------------------------}
  4727. {$S ADoCommand}
  4728.  
  4729. PROCEDURE TCalcTypingCommand.UndoIt; OVERRIDE;
  4730. { If the selection has changed since this command was created, restore it to the
  4731.   target cell before Undoing. }
  4732.  
  4733.     VAR
  4734.         entryView:            TEntryView;
  4735.  
  4736.     BEGIN
  4737.     fCellsView.ReSelectCell(fTargetCell);                { make sure fTargetCell is selected }
  4738.     entryView := TEntryView(fTEView);
  4739.     IF (entryView.fTEditing) & (NOT entryView.fFirstEdit) THEN
  4740.         INHERITED UndoIt                                { TTE undo }
  4741.     ELSE
  4742.         BEGIN
  4743.         entryView.SwapStrings;                            { exchange current and saved strings }
  4744.         fCellsView.SetCell(fTargetCell);                { change fTargetCell's contents and redraw
  4745.                                                          it }
  4746.         END;
  4747.     END;
  4748.  
  4749. {--------------------------------------------------------------------------------------------------}
  4750. {$S ADoCommand}
  4751.  
  4752. PROCEDURE TCalcTypingCommand.RedoIt; OVERRIDE;
  4753. { If the selection has changed since this command was created, restore it to the
  4754.   target cell before Redoing. }
  4755.  
  4756.     VAR
  4757.         entryView:            TEntryView;
  4758.  
  4759.     BEGIN
  4760.     fCellsView.ReSelectCell(fTargetCell);                { make sure fTargetCell is selected }
  4761.     entryView := TEntryView(fTEView);
  4762.     IF (entryView.fTEditing) & (NOT entryView.fFirstEdit) THEN
  4763.         INHERITED RedoIt                                { TTE redo }
  4764.     ELSE
  4765.         BEGIN
  4766.         entryView.SwapStrings;                            { exchange current and saved strings }
  4767.         fCellsView.SetCell(fTargetCell);                { change fTargetCell's contents and redraw
  4768.                                                          it }
  4769.         END;
  4770.     END;
  4771.  
  4772. {--------------------------------------------------------------------------------------------------}
  4773. {$S AFields}
  4774.  
  4775. PROCEDURE TCalcTypingCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  4776.                                                         fieldAddr: Ptr;
  4777.                                                         fieldType: INTEGER)); OVERRIDE;
  4778.  
  4779.     BEGIN
  4780.     DoToField('TCalcTypingCommand', NIL, bClass);
  4781.     DoToField('fCellsView', @fCellsView, bObject);
  4782.     DoToField('fTargetCell', @fTargetCell, bPoint);
  4783.     INHERITED Fields(DoToField);
  4784.     END;
  4785.  
  4786. {***************************************************************************************************
  4787.     T C e l l E d i t C o m m a n d
  4788. ***************************************************************************************************}
  4789. {$S ASelCommand}
  4790.  
  4791. PROCEDURE TCellEditCommand.ICellEditCommand(itsDocument: TCalcDocument;
  4792.                                             itsCommand: INTEGER);
  4793.  
  4794.     VAR
  4795.         fi:            FailInfo;
  4796.  
  4797.     PROCEDURE HdlAllocationFailure(error: OSErr; message: LONGINT);
  4798.         
  4799.         BEGIN
  4800.         Free;
  4801.         END;
  4802.  
  4803.     BEGIN
  4804.     ICommand(itsCommand, itsDocument, itsDocument.fCellsView, NIL);
  4805.     fCalcDocument := itsDocument;
  4806.     CatchFailures(fi, HdlAllocationFailure);
  4807.     fSelection := MakeNewRgn;                            { copy the current selection region }
  4808.     Success(fi);
  4809.     CopyRgn(itsDocument.fCellsView.fSelections, fSelection);
  4810.     fChangesClipboard := itsCommand <> cClear;
  4811.     fCausesChange := itsCommand <> cCopy;
  4812.     END;
  4813.  
  4814. {--------------------------------------------------------------------------------------------------}
  4815. {$S ARes}
  4816.  
  4817. PROCEDURE TCellEditCommand.Free; OVERRIDE;
  4818.  
  4819.     BEGIN
  4820.     IF fSelection <> NIL THEN
  4821.         DisposeRgn(fSelection);
  4822.     fSelection := NIL;
  4823.  
  4824.     INHERITED Free;
  4825.     END;
  4826.  
  4827. {--------------------------------------------------------------------------------------------------}
  4828. {$S ADoCommand}
  4829.  
  4830. PROCEDURE TCellEditCommand.CopySelection;
  4831.  
  4832.     VAR
  4833.         clipDocument:        TCalcDocument;
  4834.         clipView:            TCellsView;
  4835.         clipRect:            Rect;
  4836.  
  4837. {--------------------------------------------------------------------------------------------------}
  4838.  
  4839.     PROCEDURE CopyRowToClipboard(aCell: GridCell);
  4840.  
  4841.         VAR
  4842.             newRow:             TRow;
  4843.  
  4844.         BEGIN
  4845.         newRow := TRow(fCalcDocument.GetRow(aCell.v).Clone);
  4846.         newRow.fNumber := newRow.fNumber - clipDocument.fRowOffset;
  4847.         clipDocument.AddRow(newRow);
  4848.         END;
  4849.  
  4850. {--------------------------------------------------------------------------------------------------}
  4851.  
  4852.     PROCEDURE CopyColumnToClipboard(aCell: GridCell);
  4853.  
  4854.         VAR
  4855.             newColumn:            TColumn;
  4856.  
  4857.         BEGIN
  4858.         newColumn := TColumn(fCalcDocument.GetColumn(aCell.h).Clone);
  4859.         newColumn.fNumber := newColumn.fNumber - clipDocument.fColumnOffset;
  4860.         clipDocument.AddColumn(newColumn);
  4861.         END;
  4862.  
  4863. {--------------------------------------------------------------------------------------------------}
  4864.  
  4865.     PROCEDURE CopyCellToClipboard(aCell: GridCell);
  4866.  
  4867.         VAR
  4868.             newCell:            TCell;
  4869.             oldCell:            TCell;
  4870.  
  4871.         BEGIN
  4872.         oldCell := fCalcDocument.GetExistingCell(aCell.v, aCell.h);
  4873.         IF oldCell <> NIL THEN
  4874.             BEGIN
  4875.             newCell := TCell(oldCell.Clone);
  4876.             clipDocument.AddCell(newCell, newCell.fRow - clipDocument.fRowOffset, newCell.fColumn -
  4877.                                  clipDocument.fColumnOffset);
  4878.             END;
  4879.         END;
  4880.  
  4881.     BEGIN
  4882.     NEW(clipDocument);
  4883.     FailNIL(clipDocument);
  4884.     clipRect := fSelection^^.rgnBBox;
  4885.     clipRect.bottom := clipRect.bottom - 1;
  4886.     clipRect.right := clipRect.right - 1;
  4887.     clipDocument.ICalcDocument(clipRect);
  4888.     clipDocument.DoInitialState;
  4889.  
  4890.     fCalcDocument.fRowsView.EachSelectedCellDo(CopyRowToClipboard);
  4891.     fCalcDocument.fColumnsView.EachSelectedCellDo(CopyColumnToClipboard);
  4892.     fCalcDocument.fCellsView.EachSelectedCellDo(CopyCellToClipboard);
  4893.  
  4894.     NEW(clipView);
  4895.     FailNIL(clipView);
  4896.     clipView.ICellsView(clipDocument, TRUE, NIL);
  4897.     clipDocument.fCellsView := clipView;
  4898.     gApplication.ClaimClipboard(clipView);
  4899.     clipView.AdjustSize;
  4900.     END;
  4901.  
  4902. {--------------------------------------------------------------------------------------------------}
  4903. {$S ADoCommand}
  4904.  
  4905. PROCEDURE TCellEditCommand.DeleteSelection;
  4906.  
  4907. {--------------------------------------------------------------------------------------------------}
  4908.  
  4909.     PROCEDURE DeleteCell(aCell: GridCell);
  4910.  
  4911.         BEGIN
  4912.         fCalcDocument.DeleteCell(aCell.v, aCell.h);
  4913.         END;
  4914.  
  4915.     BEGIN
  4916.     fCalcDocument.fCellsView.EachSelectedCellDo(DeleteCell);
  4917.     fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4918.     fCalcDocument.fCellsView.InvalidateSelection;
  4919.     END;
  4920.  
  4921. {--------------------------------------------------------------------------------------------------}
  4922. {$S ADoCommand}
  4923.  
  4924. PROCEDURE TCellEditCommand.RestoreSelection;
  4925.  
  4926.     VAR
  4927.         firstCell:            GridCell;
  4928.  
  4929. {--------------------------------------------------------------------------------------------------}
  4930.  
  4931.     PROCEDURE RestoreCell(aCell: GridCell);
  4932.  
  4933.         BEGIN
  4934.         fCalcDocument.UndeleteCell(aCell.v, aCell.h);
  4935.         END;
  4936.  
  4937.     BEGIN
  4938.     fCalcDocument.fCellsView.EachSelectedCellDo(RestoreCell);
  4939.     fCalcDocument.DoRecalculate(NOT kForceAutomatic, NOT kSetDependents);
  4940.     fCalcDocument.fCellsView.InvalidateSelection;
  4941.  
  4942.     firstCell := fCalcDocument.fCellsView.FirstSelectedCell;
  4943.     fCalcDocument.SetEntry(firstCell.v, firstCell.h);    { update entry view }
  4944.     END;
  4945.  
  4946. {--------------------------------------------------------------------------------------------------}
  4947. {$S ADoCommand}
  4948.  
  4949. PROCEDURE TCellEditCommand.ReSelect;
  4950.  
  4951.     BEGIN
  4952.     fCalcDocument.fCellsView.ReSelect(fSelection);
  4953.     END;
  4954.  
  4955. {--------------------------------------------------------------------------------------------------}
  4956. {$S ADoCommand}
  4957.  
  4958. PROCEDURE TCellEditCommand.DoIt;
  4959.  
  4960.     BEGIN
  4961.     IF fCmdNumber <> cClear THEN
  4962.         CopySelection;
  4963.     IF fCmdNumber <> cCopy THEN
  4964.         DeleteSelection;
  4965.     END;
  4966.  
  4967. {--------------------------------------------------------------------------------------------------}
  4968. {$S ADoCommand}
  4969.  
  4970. PROCEDURE TCellEditCommand.UndoIt;
  4971. { If the user has changed the selection since this command was created,
  4972.   restore it before Undoing so that the correct cells are affected. }
  4973.  
  4974.     BEGIN
  4975.     IF fCmdNumber <> cCopy THEN
  4976.         BEGIN
  4977.         ReSelect;                                        { restore command's original selection }
  4978.         RestoreSelection;
  4979.         fCalcDocument.fCellsView.ScrollSelectionIntoView(TRUE);
  4980.         END;
  4981.     END;
  4982.  
  4983. {--------------------------------------------------------------------------------------------------}
  4984. {$S ADoCommand}
  4985.  
  4986. PROCEDURE TCellEditCommand.RedoIt;
  4987. { If the user has changed the selection since this command was created,
  4988.   restore it before Redoing so that the correct cells are affected. }
  4989.  
  4990.     BEGIN
  4991.     IF fCmdNumber <> cCopy THEN
  4992.         BEGIN
  4993.         ReSelect;                                        { restore command's original selection }
  4994.         DeleteSelection;
  4995.         fCalcDocument.fCellsView.ScrollSelectionIntoView(TRUE);
  4996.         END;
  4997.     END;
  4998.  
  4999. {--------------------------------------------------------------------------------------------------}
  5000. {$S ADoCommand}
  5001.  
  5002. PROCEDURE TCellEditCommand.Commit;
  5003.  
  5004.     BEGIN
  5005.     fCalcDocument.FreeDeletedCells;
  5006.     END;
  5007.  
  5008. {--------------------------------------------------------------------------------------------------}
  5009. {$S AFields}
  5010.  
  5011. PROCEDURE TCellEditCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  5012.                                                       fieldAddr: Ptr;
  5013.                                                       fieldType: INTEGER)); OVERRIDE;
  5014.  
  5015.     BEGIN
  5016.     DoToField('TCellEditCommand', NIL, bClass);
  5017.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  5018.     DoToField('fSelection', @fSelection, bRgnHandle);
  5019.     INHERITED Fields(DoToField);
  5020.     END;
  5021.  
  5022. {***************************************************************************************************
  5023.     T C e l l P a s t e C o m m a n d
  5024. ***************************************************************************************************}
  5025. {$S ASelCommand}
  5026.  
  5027. PROCEDURE TCellPasteCommand.ICellPasteCommand(itsDocument: TCalcDocument);
  5028.  
  5029.     VAR
  5030.         fi:            FailInfo;
  5031.  
  5032.     PROCEDURE HdlAllocationFailure(error: OSErr; message: LONGINT);
  5033.         
  5034.         BEGIN
  5035.         Free;
  5036.         END;
  5037.  
  5038.     BEGIN
  5039.     {$IFC qDebug}
  5040.     IF NOT Member(gClipView, TCellsView) THEN
  5041.         ProgramBreak('Attempt to paste a non-TCellsView clipboard');
  5042.     {$ENDC}
  5043.     ICommand(cPaste, itsDocument, itsDocument.fCellsView, NIL);
  5044.     fCalcDocument := itsDocument;
  5045.     CatchFailures(fi, HdlAllocationFailure);
  5046.     fSelection := MakeNewRgn;                            { copy the current selection region }
  5047.     Success(fi);
  5048.     CopyRgn(itsDocument.fCellsView.fSelections, fSelection);
  5049.     fClipDocument := TCellsView(gClipView).fCalcDocument;
  5050.     fReplacedCells := NewList;
  5051.     FailNIL(fReplacedCells);
  5052.     {$IFC qDebug}
  5053.     fReplacedCells.SetEltType('TCell');
  5054.     {$ENDC}
  5055.     END;
  5056.  
  5057. {--------------------------------------------------------------------------------------------------}
  5058. {$S ADoCommand}
  5059.  
  5060. PROCEDURE TCellPasteCommand.Free; OVERRIDE;
  5061.  
  5062.     BEGIN
  5063.     IF fSelection <> NIL THEN
  5064.         DisposeRgn(fSelection);
  5065.     fSelection := NIL;
  5066.  
  5067.     fReplacedCells := FreeListIfObject(fReplacedCells);
  5068.  
  5069.     INHERITED Free;
  5070.     END;
  5071.  
  5072. {--------------------------------------------------------------------------------------------------}
  5073. {$S ADoCommand}
  5074.  
  5075. PROCEDURE TCellPasteCommand.DoIt;
  5076.  
  5077.     VAR
  5078.         r:                    INTEGER;                    { Can't use RowNumber or ColumnNumber }
  5079.         c:                    INTEGER;                    { … because they may be out of range }
  5080.         fi:                 FailInfo;
  5081.  
  5082. {--------------------------------------------------------------------------------------------------}
  5083.  
  5084.     PROCEDURE PasteCell(aCell: GridCell);
  5085.  
  5086.         VAR
  5087.             sourceCell:         TCell;
  5088.             replacedCell:        TCell;
  5089.             destCell:            TCell;
  5090.  
  5091.         BEGIN
  5092.         destCell := fCalcDocument.GetCell(aCell.v, aCell.h);
  5093.         replacedCell := TCell(destCell.Clone);
  5094.         fReplacedCells.InsertLast(replacedCell);
  5095.  
  5096.         sourceCell := fClipDocument.GetCell(r, c);
  5097.         c := c + 1;
  5098.         IF c > fClipDocument.fNoOfColumns THEN
  5099.             BEGIN
  5100.             c := 1;
  5101.             r := r + 1;
  5102.             IF r > fClipDocument.fNoOfRows THEN
  5103.                 r := 1;
  5104.             END;
  5105.  
  5106.         destCell.CopyContents(sourceCell);                { copy the necessary fields }
  5107.         END;
  5108.  
  5109. {--------------------------------------------------------------------------------------------------}
  5110.  
  5111.     PROCEDURE HdlPasteFailure(error: OSErr;
  5112.                               message: LONGINT);
  5113.     { We ran out of memory and couldn't complete the paste.
  5114.       So, let's back out the partial paste. All or nothing! }
  5115.  
  5116. {--------------------------------------------------------------------------------------------------}
  5117.  
  5118.         PROCEDURE RestoreCell(replacedCell: TCell);
  5119.  
  5120.             VAR
  5121.                 pastedCell:         TCell;
  5122.  
  5123.             BEGIN
  5124.             pastedCell := fCalcDocument.GetCell(replacedCell.fRow, replacedCell.fColumn);
  5125.             IF replacedCell.IsEmpty THEN                { free up memory used by empty cell }
  5126.                 BEGIN
  5127.                 fCalcDocument.DeleteCell(pastedCell.fRow, pastedCell.fColumn);
  5128.                 fCalcDocument.FreeCell(pastedCell);
  5129.                 END
  5130.             ELSE
  5131.                 pastedCell.CopyContents(replacedCell);
  5132.             FreeIfObject(replacedCell);                            { free up memory used by replacement cell }
  5133.             replacedCell := NIL;
  5134.             END;
  5135.  
  5136.         BEGIN
  5137.         fReplacedCells.Each(RestoreCell);
  5138.         fReplacedCells.DeleteAll;
  5139.         UpdateViews;
  5140.         END;
  5141.  
  5142.     BEGIN                                                { TCellPasteCommand.DoIt }
  5143.     CatchFailures(fi, HdlPasteFailure);
  5144.     r := 1;
  5145.     c := 1;
  5146.     fCalcDocument.fCellsView.EachSelectedCellDo(PasteCell);
  5147.     Success(fi);
  5148.     UpdateViews;
  5149.     END;
  5150.  
  5151. {--------------------------------------------------------------------------------------------------}
  5152. {$S ADoCommand}
  5153.  
  5154. PROCEDURE TCellPasteCommand.UndoIt;
  5155.  
  5156. {--------------------------------------------------------------------------------------------------}
  5157.  
  5158.     PROCEDURE RestoreCell(replacedCell: TCell);
  5159.  
  5160.         VAR
  5161.             pastedCell:         TCell;
  5162.  
  5163.         BEGIN
  5164.         pastedCell := fCalcDocument.GetCell(replacedCell.fRow, replacedCell.fColumn);
  5165.         pastedCell.CopyContents(replacedCell);
  5166.         END;
  5167.  
  5168.     BEGIN
  5169.     fCalcDocument.fCellsView.ReSelect(fSelection);        { restore original selection }
  5170.     fReplacedCells.Each(RestoreCell);
  5171.     UpdateViews;
  5172.     END;
  5173.  
  5174. {--------------------------------------------------------------------------------------------------}
  5175. {$S ADoCommand}
  5176.  
  5177. PROCEDURE TCellPasteCommand.RedoIt;
  5178.  
  5179.     VAR
  5180.         r:                    INTEGER;                    { Can't use RowNumber or ColumnNumber }
  5181.         c:                    INTEGER;                    { … because they may be out of range }
  5182.  
  5183. {--------------------------------------------------------------------------------------------------}
  5184.  
  5185.     PROCEDURE RepasteCell(aCell: GridCell);
  5186.  
  5187.         VAR
  5188.             sourceCell:         TCell;
  5189.             destCell:            TCell;
  5190.  
  5191.         BEGIN
  5192.         destCell := fCalcDocument.GetCell(aCell.v, aCell.h);
  5193.         sourceCell := fClipDocument.GetCell(r, c);
  5194.         c := c + 1;
  5195.         IF c > fClipDocument.fNoOfColumns THEN
  5196.             BEGIN
  5197.             c := 1;
  5198.             r := r + 1;
  5199.             IF r > fClipDocument.fNoOfRows THEN
  5200.                 r := 1;
  5201.             END;
  5202.  
  5203.         destCell.CopyContents(sourceCell);
  5204.         END;
  5205.  
  5206.     BEGIN
  5207.     fCalcDocument.fCellsView.ReSelect(fSelection);        { restore original selection }
  5208.     r := 1;
  5209.     c := 1;
  5210.     fCalcDocument.fCellsView.EachSelectedCellDo(RepasteCell);
  5211.     UpdateViews;
  5212.     END;
  5213.  
  5214. {--------------------------------------------------------------------------------------------------}
  5215. {$S ADoCommand}
  5216.  
  5217. PROCEDURE TCellPasteCommand.UpdateViews;
  5218.  
  5219.     VAR
  5220.         aString:            Str255;
  5221.         aCell:                GridCell;
  5222.  
  5223.     BEGIN
  5224.     WITH fCalcDocument DO
  5225.         BEGIN
  5226.         DoRecalculate(NOT kForceAutomatic, kSetDependents);
  5227.         fCellsView.InvalidateSelection;
  5228.  
  5229.         aCell.h := fEditColumn;
  5230.         aCell.v := fEditRow;
  5231.         IF fCellsView.IsCellSelected(aCell) THEN
  5232.             BEGIN
  5233.             fEditCell := GetCell(aCell.v, aCell.h);
  5234.             fEditCell.GetAsString(aString);
  5235.             fEntryView.SetToString(aString);
  5236.             END;
  5237.         END;
  5238.     END;
  5239.  
  5240. {--------------------------------------------------------------------------------------------------}
  5241. {$S AFields}
  5242.  
  5243. PROCEDURE TCellPasteCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  5244.                                                        fieldAddr: Ptr;
  5245.                                                        fieldType: INTEGER)); OVERRIDE;
  5246.  
  5247.     BEGIN
  5248.     DoToField('TCellPasteCommand', NIL, bClass);
  5249.     DoToField('fClipDocument', @fClipDocument, bObject);
  5250.     DoToField('fCalcDocument', @fCalcDocument, bObject);
  5251.     DoToField('fSelection', @fSelection, bRgnHandle);
  5252.     DoToField('fReplacedCells', @fReplacedCells, bObject);
  5253.     INHERITED Fields(DoToField);
  5254.     END;
  5255.